> For the complete documentation index, see [llms.txt](https://docs.edgegap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.edgegap.com/zh/docs/tools-and-integrations/docker.md).

# Docker 与容器

为什么 Edgegap 采用容器运行游戏服务器，以及在构建第一个服务器镜像前如何配置 Docker。

{% columns %}
{% column width="25%" %}

<figure><img src="https://3334189208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-e6111f686dccc8bebc29f2f10fe2ce093f9c2b9c%2Fdocker.png?alt=media" alt="" width="100"><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="75%" %}
Docker 是一个用于开发、交付和运行应用程序的开放平台。Docker 让你能够将应用程序与基础设施分离，从而快速交付软件。
{% endcolumn %}
{% endcolumns %}

## 为什么使用 Docker？

在一个开发者团队中工作意味着要共享代码。当出现问题时，您最不想听到的就是“在我的机器上可以运行”。游戏服务器必须能够在任何机器上可靠运行，因为成功的游戏服务器会在世界各地成千上万台服务器机器上运行。

为了帮助使您的服务器可靠，我们使用 Docker —— 一种虚拟化软件，确保您的所有服务器代码依赖项直到操作系统级别始终完全相同，无论服务器如何或在哪里启动。

{% hint style="info" %}
我们建议观看 [“永远不要本地安装”（视频）](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **使用 Docker 不需要使用 Dockerhub**。Docker ≠ Dockerhub。把 Docker 想象成一个编程引擎，把 Dockerhub 想成它的应用商店。
{% endhint %}

## 容器

一个 **容器是软件的标准单元，它将代码打包起来** 以及它的所有依赖项，使应用程序能够在不同计算环境之间快速且可靠地运行。容器将软件与其环境隔离开来，并确保即使在例如开发和预发布环境之间存在差异时，也能保持一致运行。

\
一旦你运行打包好的 docker 镜像，它们就会变成：

* **容器** 如果在 Docker Desktop 或 Docker Engine 中运行（通常在本地），
* &#x20;[部署](/zh/learn/bian-pai/deployments.md) 如果在 Edgegap 上运行（Edge Cloud 和 Private Fleet 均适用）。

容器在 Linux（或 Docker Desktop 中）上原生运行，并与其他容器共享主机机器的内核。它运行一个独立进程，所占内存不比任何其他可执行程序更多，因此非常轻量。

<figure><img src="https://3334189208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-f150d345ddba740a7babd5338aca3f557cc1886c%2Fcontainer-architecture.png?alt=media" alt=""><figcaption></figcaption></figure>

## **试试看**

要使用 docker 并在本地构建或运行 docker 镜像，你需要安装 Docker：

<details>

<summary><a href="https://www.docker.com/products/docker-desktop/">安装 Docker Desktop（或 Docker CLI）</a></summary>

* [从官方来源安装 Docker Desktop](https://www.docker.com/products/docker-desktop/) （无需账户）。
* 完成安装后重启计算机。

</details>

安装完成后，你可以打开任意终端并尝试运行一个测试镜像。

```sh
docker run -d -p 80:80 --name speedtest edgegap/speedtest-edge
```

这将自动执行以下步骤：

1. 从 Edgegap 仓库下载 speedtest 镜像（仅第一次）。
2. 在你的机器上使用此镜像创建并启动一个新容器。
3. 将其命名为“speedtest”（使用 `--name` 参数）。
4. 暴露一个 [应用与版本](/zh/learn/bian-pai/application-and-versions.md#port-mapping) 以连接你机器的端口 `80`  到容器的端口 `80` ，从而让你的机器可以访问容器。

✅ 打开 [http://localhost:80](http://localhost/) 并在你偏好的浏览器中确认容器已成功启动。

当容器运行后，我们可以进行基本交互——重启、停止、监控。&#x20;

首先，让我们使用你喜欢的终端查看 docker 引擎上正在运行的内容。

```sh
docker ps
```

这将打印正在运行的容器信息，例如：

```
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                NAMES
dbf4d3734111        edgegap/speedtest-edge   "docker-php-entrypoi…"   29 minutes ago      Up 29 minutes       0.0.0.0:80->80/tcp   speedtest
```

你可以运行任意数量的容器。

让我们尝试获取有关容器的更多信息：

```sh
docker container inspect speedtest
```

你也可以检查你的机器与容器之间共享的网络。

```sh
docker network ls
```

这将打印由你机器上的 docker 引擎运行的网络信息。

```
NETWORK ID          NAME                DRIVER              SCOPE
67b24038b9ca        bridge              bridge              local
6f7fe43a489d        host                host                local
3d80cdb86a7e        none                null                local
```

你也可以更详细地检查单个网络：

```sh
docker network inspect 67b24038b9ca
# 其中 678b24038b9ca 是连接到你容器的网络
```

测试完容器后，请务必将其停止，以回收该容器用于运行的资源（CPU 和 RAM）：

```sh
docker container stop speedtest
```

## SSH 隧道

要深入排查服务器问题，你可以在镜像中暴露 SSH 服务，并像连接任何远程主机或虚拟机一样连接到容器或部署。

{% hint style="danger" %}
**切勿在生产部署中暴露 SSH 服务** ——这会带来严重的安全问题。
{% endhint %}

### 本地测试

我们需要对你的 Dockerfile 做一些修改。让我们安装 OpenSSH 服务、创建一个带密码的用户，并启用该服务。

{% hint style="success" %}
**Dockerfile 命令的顺序很重要！** [Docker 会缓存各层以加快构建速度。](https://docs.docker.com/build/cache/) 将像 `RUN` 和 `COPY` 这样的未缓存层放在 Dockerfile 的末尾（在 `CMD`).
{% endhint %}

之前）

{% tabs %}
{% tab title="Ubuntu 基础镜像" %}

```dockerfile
RUN apt-get update
RUN apt-get install openssh-server sudo -y

RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1000
RUN echo 'tester:$ecureP@ss' | chpasswd
# 别忘了修改你的密码 ^

EXPOSE 22
```

{% endtab %}

{% tab title="Alpine 基础镜像" %}

```dockerfile
RUN apk --update add --no-cache openssh bash
RUN sed -i s/#PermitRootLogin.*/PermitRootLogin\ yes/ /etc/ssh/sshd_config

RUN echo "tester:$ecureP@ss" | chpasswd
# 别忘了修改你的密码 ^

EXPOSE 22
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
`EXPOSE` 不会自动发布端口，它只是给 docker 引擎和开发者的一个提示。
{% endhint %}

我们还需要在容器中启动 ssh 服务：

{% tabs %}
{% tab title="从 Dockerfile 开始（Unity 插件）" %}
{% code title="Dockerfile" %}

```docker
CMD [ \
  "/bin/bash", "-c", \
  "env;service ssh start;/path/to/server-executable" \
]
# 打印环境变量，启动 SSH，然后启动游戏服务器
```

{% endcode %}
{% endtab %}

{% tab title="从 .sh shell 脚本开始（Unreal）" %}
{% code title="StartServer.sh" %}

```sh
service ssh start
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
你不能使用 `RUN` 命令来启动 SSH 服务，因为它只在构建时执行。
{% endhint %}

✅ 现在 `docker build`，并测试 `docker run`  在本地，然后使用 `ssh localhost:22`.

{% hint style="danger" %}
:x: **不要 - 覆盖现有标签或使用 `最新` 标签** - 这将部署一个过时的缓存。\
:white\_check\_mark: **务必 - 始终增加你的版本标签** 并部署新构建。
{% endhint %}

{% hint style="success" %}
**先在本地（并且安全地）排查问题，而不要将镜像推送到仓库。**
{% endhint %}

### 在云端部署

如果你没有成功使用 [#test-locally](#test-locally "mention")，你可以在部署环境中进行测试。

✅ [登录你的 docker 仓库](https://app.edgegap.com/registry-management/repositories/list) 和  `docker push`  新标签：

{% code title="" %}

```sh
username='robot$<REGISTRY_ORGANIZATION_ID>+client-push';
token='<REGISTRY_TOKEN>';

project='<REGISTRY_PROJECT>';
image='<MY_IMAGE_NAME>';
tag='<MY_TAG>';

echo "$token" | docker login registry.edgegap.com -u "$username" --password-stdin 2>&1;
docker push "${registry}/${project}/${image}:${tag}";
```

{% endcode %}

✅ [通过仪表板为此镜像创建一个新的测试应用版本。](https://app.edgegap.com/application-management/applications/list)

* 添加一个 22/TCP 的端口映射，以对应 `-p` 选项来自 `docker run`.

✅ [Deploy](https://app.edgegap.com/deployment-management/deployments/create) 并使用分配给 `ssh`.

的外部 SSH 端口的 URL 或 IP。✅ 测试完成后，停止部署并删除你的测试镜像。
