Docker 容器的工作原理

已完成

在这之前,你发现了容器是用于分发应用的单元。 你还了解到容器采用开发者团队和运营团队使用的标准化格式。

在示例中,你要开发一个订单跟踪门户,供公司的各个专卖店使用。 生成 Docker 映像后,现在由运营团队负责订单跟踪门户的部署、更新推出和管理。

在之前的单元中,你了解了如何生成 Docker 映像。 在这里,你将简单了解下 Docker 容器的生命周期以及如何管理容器。 你还将了解如何考虑为容器配置数据存储和网络选项。

如何管理 Docker 容器

Docker 容器具有可用于管理和跟踪容器状态的生命周期。

Diagram that shows the lifecycle of a container and the transition between the lifecycle phases.

若要将容器置于运行状态,请使用 run 命令。 还可重启已在运行的容器。 重启容器时,容器将收到一个终止信号,以允许任何正在运行的进程在容器的内核终止之前正常关闭。

容器在暂停、停止或终止之前将被视为处于运行状态。 但是,容器也可能会自行退出运行状态。 当正在运行的进程完成或者进程进入错误状态时,容器可自行退出。

若要暂停正在运行的容器,请使用 pause 命令。 此命令会暂停容器中的所有进程。

若要停止正在运行的容器,请使用 stop 命令。 Stop 命令通过向正在运行的进程发送 termination 信号来正常关闭该进程。 进程关闭后,容器的内核将终止。

如果需要终止容器,请使用 kill 命令发送终止信号。 容器的内核会捕获该终止信号,但正在运行的进程不会。 此命令会强制终止容器中正在运行的进程。

最后,若要删除处于停止状态的容器,请使用 remove 命令。 删除容器后,将销毁存储在容器中的所有数据。

如何查看可用容器

若要列出正在运行的容器,请使用 docker ps 命令。 若要查看处于所有状态的所有容器,请传递 -a 参数。

下面是一个示例:

docker ps -a

该命令的输出如下所示:

CONTAINER ID    IMAGE        COMMAND         CREATED       STATUS           PORTS        NAMES
d93d40cc1ce9    tmp-ubuntu:latest  "dotnet website.dll …"  6 seconds ago    Up 5 seconds        8080/tcp      happy_wilbur
33a6cf71f7c1    tmp-ubuntu:latest  "dotnet website.dll …"  2 hours ago     Exited (0) 9 seconds ago            adoring_borg

需要查看前述输出中的以下三个项:

  • IMAGE 列中列出的映像名称;在此示例中为 tmp-ubuntu: latest。 请注意,你可以从同一映像创建多个容器。 这是一种强大的管理功能,可用于在解决方案中实现缩放。

  • STATUS 列中列出的容器状态。 在本例中,一个容器正在运行,一个容器已退出。 容器的状态通常是容器运行状况的第一个指标。

  • NAMES 列中列出的容器名称。 除了第一列中的容器 ID 之外,容器还会接收名称。 在本例中,由于你没有为每个容器显式提供名称,因此,Docker 为容器提供了随机名称。 若要使用 --name 标志为容器提供显式名称,请使用 run 命令。

为什么要为容器命名?

借助此功能,可运行同一映像的多个容器实例。 容器名称是唯一的,这意味着如果指定了某一名称,则不能重复使用该名称来创建新的容器。 重复使用特定名称的唯一方法是删除之前的容器。

如何运行容器

若要启动容器,请使用 docker run 命令。 只需按名称或 ID 指定要运行的映像,即可从映像启动容器。 通过此方式启动的容器提供交互式体验。

此处,若要在网站处于后台的情况下运行容器,请添加 -d 标志。

docker run -d tmp-ubuntu

在此示例中,该命令仅返回新容器的 ID。

指定要运行的映像后,Docker 将查找该映像,从该映像加载容器,并执行指定为入口点的命令。 此时,容器可供管理。

如何暂停容器

若要暂停容器,请运行 docker pause 命令。 下面是一个示例:

docker pause happy_wilbur

暂停容器会暂停所有进程。 通过此命令,容器可在后续阶段继续执行进程。 docker unpause 命令将取消挂起指定容器中的所有进程。

如何重启容器

若要重启容器,请运行 docker restart 命令。 下面是一个示例:

docker restart happy_wilbur

容器会收到 stop 命令,然后是 start 命令。 如果容器未响应 stop 命令,将发送 kill 信号。

如何停止容器

若要停止正在运行的容器,请运行 docker stop 命令。 下面是一个示例:

docker stop happy_wilbur

stop 命令会将终止信号发送到容器和容器中正在运行的进程。

如何删除容器

若要删除容器,请运行 docker rm 命令。 下面是一个示例:

docker rm happy_wilbur

删除容器后,将销毁容器中的所有数据。 考虑存储数据时,始终将容器视为临时容器非常重要。

Docker 容器存储配置

如前文所述,如果容器中的应用需要存储数据,则始终将容器视为临时容器。

假设我们的跟踪门户在应用根的子文件夹(即直接到容器文件系统)中创建了一个日志文件。 当应用将数据写入日志文件时,系统会将数据写入可写容器层。

虽然此方法很有效,但遗憾的是,它存在一些缺点。

  • 容器存储是临时的。

    日志文件不会在容器实例之间存留。 例如,假设你停止并删除容器。 当你启动新容器实例时,新实例将基于指定的映像,而以前的所有数据将丢失。 请记住,删除容器时,将随容器销毁容器中的所有数据。

  • 容器存储与底层主机耦合。

    容器与底层主机耦合,因此很难从容器访问或移动日志文件。 必须连接到容器实例来访问该文件。

  • 容器存储驱动程序性能较低。

    容器实现存储驱动程序,以允许应用写入数据。 此驱动程序引入额外抽象来与主机操作系统内核通信,比直接写入主机文件系统的性能要低。

容器可以使用两种选项来保持数据。 第一种选项是使用卷,第二种选项则是绑定装载。

什么是卷?

卷存储在主机文件系统上的特定文件夹位置。 选择一个文件夹,确保其中的数据只能由 Docker 进程修改。

Docker 通过运行 docker volume create 命令创建和管理新卷。 此命令可以构成 Dockerfile 定义的一部分,这意味着你可以在容器创建过程中创建卷。 如果在第一次尝试将卷装载到容器中时,该卷不存在,则 Docker 将创建该卷。

卷存储在主机文件系统上的目录中。 Docker 将装载并管理容器中的卷。 装载后,这些卷将与主机隔离。

多个容器可以同时使用相同的卷。 当容器停止使用卷时,不会自动删除这些卷。

在本例中,你可以在容器主机上创建一个目录,并在创建跟踪门户容器时将此卷装载到容器中。 当跟踪门户记录数据时,你可以通过容器主机的文件系统访问此信息。 即使删除了容器,你仍可以访问此日志文件。

Docker 还为第三方公司提供了一种生成加载项以用作卷的方法。 例如,Azure 存储提供了一个插件,用于将 Azure 存储装载为 Docker 容器上的卷。

什么是绑定装载?

绑定装载在概念上与卷相同;但是,你可以在主机上装载任何文件或文件夹,而不是使用特定文件夹。 你还希望主机可以更改这些装载的内容。 与卷一样,如果你要装载的绑定不存在于主机上,系统将创建该绑定装载。

与卷相比,绑定装载的功能有限,虽然性能更高,但仍依赖于具主机上的特定文件夹结构。

卷是公认的用于容器的首选数据存储策略。

对于 Windows 容器,可以使用另一个选项:可以将 SMB 路径装载为卷,并将其提供给容器。 这可以让不同主机上的容器使用相同的持久存储。

Docker 容器网络配置

默认 Docker 网络配置允许在 Docker 主机上隔离容器。 借助此功能,可以生成和配置可彼此安全通信的应用。

Docker 为 Linux 和 Windows 提供不同的网络设置。

对于 Linux,有六个预配置的网络选项:

  • 桥接
  • 主机
  • 覆盖
  • IPvLan
  • MACvLan

对于 Windows,有六个预配置的网络选项:

  • NAT(网络地址转换)
  • 透明
  • 覆盖
  • L2Bridge
  • L2Tunnel

可以根据容器的网络要求选择要向其应用的网络配置。

什么是桥接网络?

启动容器而未指定任何其他网络配置时,默认对容器应用桥接网络配置。 此网络是容器使用的内部专用网络,它将容器网络与 Docker 主机网络隔离。

桥接网络中的每个容器都分配有一个 IP 地址和子网掩码,主机名默认为容器名称。 允许连接到默认桥接网络的容器按 IP 地址访问其他通过桥接网络连接的容器。 桥接网络不允许使用主机名在容器之间进行通信。

默认情况下,Docker 不会发布任何容器端口。 若要在容器端口和 Docker 主机端口之间启用端口映射,请使用 Docker 端口 --publish 标志。

publish 标志可有效配置映射端口的防火墙规则。

在本例中,浏览到端口 80 的客户端可以访问你的跟踪门户。 必须将端口 80 从容器映射到主机上的可用端口。 你在主机上打开了端口 8080,因此可设置如下标志:

--publish 8080:80

任何浏览到 Docker 主机 IP 和端口 8080 的客户端都可以访问跟踪门户。

除了特定于 Linux 的配置,Windows 主机上的 NAT 网络的功能与桥接网络相同。 此外,NAT 是 Windows 上的默认网络,除非另行指定,否则所有容器都将连接到 NAT。

什么是主机网络?

通过主机网络,你可以直接在主机网络上运行容器。 此配置在网络级别有效地消除了主机与容器之间的隔离。

在本例中,假设你决定将网络配置更改为主机网络选项。 仍可使用主机 IP 访问跟踪门户。 现在,可以使用已知端口 80,而不是映射的端口。

请记住,容器只能使用主机尚未使用的端口。

在 Windows 上,主机网络不可用。 在 Windows 主机上,无法在主机和容器之间共享相同的 IP 地址(网络堆栈)。 NAT 网络的功能非常类似于桥接网络,“覆盖”选项为容器提供主机所在网络中的一个 IP 地址,但不是同一个 IP 地址。

覆盖和其他网络选项

对于更高级的方案,Linux 和 Windows 都提供了其他网络选项。 例如,覆盖选项从主机网络创建虚拟交换机,使该网络上的容器可以从 DHCP 服务器获取 IP 地址,或使用该网段的 IP 地址进行操作。 此外,通过 Docker,第三方供应商可以创建网络插件。

什么是“无”网络?

若要禁止容器使用网络,请使用“无”网络选项。 如果应用程序不使用网络,或者你只想验证应用程序是否在容器中按预期运行,这可能很有用。

操作系统注意事项

请记住,各桌面操作系统上的 Docker 网络配置选项存在差异。 例如,使用桥接网络时,Docker0 网络接口在 macOS 上不可用;Windows 和 macOS 桌面版均不支持使用主机网络配置。

这些差异可能会影响开发者配置用于管理容器开发的工作流。 此外,容器业务流程协调程序还可能在 Docker 设置的基础上提供其他网络配置。

知识检查

1.

使用 --publish 80:8080 标志启动容器。 以下哪个选项最有可能是为容器配置的网络?

2.

以下哪个存储选项是允许主机和容器共享文件以管理名称服务器解析(例如 Linux 上的 resolve.conf 文件)的最佳选择?