13 容器编制 #
13.1 简介 #
现在您已充分了解如何在桌面或服务器上处理容器,接下来可以进一步了解如何在生产环境中使用容器。在生产环境中,您可能需要管理多个容器,包括单个容器主机或多个容器主机上的容器。要管理多个容器,必须将一个或多个容器分组到一个 Pod 中,使它们能够共享存储和网络资源;同时,必须制定有关如何部署和运行容器的规范。简而言之,Pod 会将包含多个容器的应用程序封装成一个单元。 Pod 概念是由 Kubernetes 引入的。不过,Podman(代表 Pod Manager)使用与 Kubernetes 相同的定义。
13.2 包含 Podman 的单容器主机 #
13.2.1 体系结构 #
Pod 是共享同一名称空间、端口和网络连接的一组容器。通常,一个 Pod 中的容器可以直接相互通讯。每个 Pod 包含一个基础架构容器 (INFRA),其用途是保存名称空间。INFRA 还允许 Podman 在 Pod 中添加其他容器。端口绑定、cgroup-parent 值和内核名称空间全都指派给基础架构容器。因此,以后无法更改这些值。
Pod 中的每个容器具有自身的监视程序实例。该监视程序监视容器的进程,如果该容器消亡,监视程序将保存其退出代码。该程序还保持打开特定容器的 tty 接口。当 Podman 退出时,您可以使用该监视程序以分离模式运行容器,因为此程序会持续运行,并允许您稍后附加 tty。
13.2.2 podman pod #
podman pod 是用于创建、去除、查询和检查 Pod 的命令行工具。您可以在官方上游文档中查看所有子命令。
13.2.3 创建和列出 Pod #
podman pod create 将创建一个使用随机名称的 Pod,但您可以使用 --name 参数为 Pod 指派所需的名称。
# podman pod create 344940492c00b6a19ececbc5b109351bf0a3b8b19b3c279a097da7a653c592d0
可以使用 podman pod list 命令列出 Pod:
# podman pod list POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS 344940492c00 suspicious_curie Created 2 minutes ago 617d7e3ce399 1
还可以列出所有容器及其关联的 Pod:
# podman ps -a --pod CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME 617d7e3ce399 localhost/podman-pause:4.3.1-1669118400 5 minutes ago Created 344940492c00-infra 344940492c00 suspicious_curie
创建的 Pod 包含一个通过 localhost/podman-pause:4.x
名称标识的 infra 容器。此容器的用途是保留与 Pod 关联的名称空间,并使 Podman 能够在 Pod 中添加其他容器。
13.2.4 运行容器并将其添加到 Pod #
使用 podman run --pod 命令可以运行容器并将其添加到所需的 Pod。例如,以下命令运行一个基于 suse/sle15 映像的容器,并将该容器添加到 suspicious_curie
Pod:
# podman run -d --pod suspicious_curie registry.suse.com/bci/bci-base sleep 1h 8f5af62a7c385bbd1a3a5cc3a53a8d0f8cf942adc26a065960d4232fcc93ac98
WARN[0005] Path "/etc/SUSEConnect" from "/etc/containers/mounts.conf" doesn't exist, skipping WARN[0005] Failed to mount subscriptions, skipping entry in /etc/containers/mounts.conf: open /etc/zypp/credentials.d/SCCcredentials: permission denied
上面的命令会添加一个休眠 60 分钟然后退出的容器。再次运行 podman ps -a --pod 命令,您应该会看到该 Pod 现在包含两个容器。
还可以检查 podman pod ps 命令的输出:
# podman pod ps POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS 344940492c00 suspicious_curie Running 21 minutes ago 617d7e3ce399 2
13.2.5 停止 Pod 或 Pod 中的容器 #
让我们停止新建的名为 Objective_jemison 的容器
# podman ps -a --pod CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME 617d7e3ce399 localhost/podman-pause:4.3.1-1669118400 14 minutes ago Up 4 minutes ago 344940492c00-infra 344940492c00 suspicious_curie 8f5af62a7c38 registry.suse.com/bci/bci-base:latest sleep 1h 4 minutes ago Up 4 minutes ago objective_jemison 344940492c00 suspicious_curie # podman stop objective_jemison objective_jemison # podman pod ps POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS 344940492c00 suspicious_curie Degraded 25 minutes ago 617d7e3ce399 2 # podman ps -a --pod CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME 617d7e3ce399 localhost/podman-pause:4.3.1-1669118400 25 minutes ago Up 15 minutes ago 344940492c00-infra 344940492c00 suspicious_curie 8f5af62a7c38 registry.suse.com/bci/bci-base:latest sleep 1h 15 minutes ago Exited (137) 14 seconds ago objective_jemison 344940492c00 suspicious_curie
还可以使用 podman pod stop 停止 Pod 及其所有容器
# podman pod stop suspicious_curie 344940492c00b6a19ececbc5b109351bf0a3b8b19b3c279a097da7a653c592d0 # podman ps -ap CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME 617d7e3ce399 localhost/podman-pause:4.3.1-1669118400 29 minutes ago Exited (0) 7 seconds ago 344940492c00-infra 344940492c00 suspicious_curie 8f5af62a7c38 registry.suse.com/bci/bci-base:latest sleep 1h 19 minutes ago Exited (137) 3 minutes ago objective_jemison 344940492c00 suspicious_curie
当然,也可以使用 sudo podman start yourcontainername、podman pod start yourpodname 或 podman pod restart yourpodname 来启动和重启动任何 Pod 及其容器。
13.2.6 去除 Pod #
可以通过两种方式去除删除 Pod。可以使用 podman pod rm
命令去除一个或多个 Pod。或者,可以使用 podman pod prune
命令去除所有已停止的 Pod。要去除一个或多个 Pod,请如下所示运行 podman pod rm
命令:
# podman pod rm POD
POD 可以是 Pod 名称或 Pod ID。要去除所有当前已停止的 Pod,请使用 podman pod prune
命令。在运行 podman pod prune
命令之前,请确保所有已停止的 Pod 是您想要去除的 Pod,否则可能会去除仍在使用的 Pod。
13.2.7 为 Pod 创建 systemd 单元 #
使用容器运行时可以轻松启动作为单个容器分发的应用程序。但是,如果您需要运行包含多个容器的应用程序,或者需要在系统引导时自动启动应用程序,并在应用程序崩溃后将其重启动,事情会变得更复杂。虽然 Kubernetes 之类的容器编制工具正好可以解决这样的需求,但它们旨在用于包含数百个节点的高度分布式的可缩放系统,而不适合用于单台计算机。systemd 和 Podman 更适合单计算机方案,因为它们不会在现有设置中增加另一层复杂性。
13.2.7.1 概述 #
从版本 1.3.0 开始,Podman 支持使用 podman generate systemd
子命令创建 systemd 单元文件。该子命令创建一个 systemd 单元文件,使您可以通过 systemd 控制容器或 Pod。使用该单元文件,可以在引导时启动容器或 Pod,在发生故障时自动重启动容器或 Pod,并将其日志保存在 journald 中。
13.2.7.2 创建新的 Systemd 单元文件 #
以下示例使用一个简单的 NGINX 容器:
❯ podman run -d --name web -p 8080:80 docker.io/nginx c0148d8476418a2da938a711542c55efc09e4119909aea70e287465c6fb51618
可如下所示为容器生成 systemd 单元:
❯ podman generate systemd --name --new web # container-web.service # autogenerated by Podman 4.2.0 # Tue Sep 13 10:58:54 CEST 2022 [Unit] Description=Podman container-web.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=%t/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/%n.ctr-id ExecStart=/usr/bin/podman run \ --cidfile=%t/%n.ctr-id \ --cgroups=no-conmon \ --rm \ --sdnotify=conmon \ --replace \ -d \ --name web \ -p 8080:80 docker.io/nginx ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id Type=notify NotifyAccess=all [Install] WantedBy=default.target
Podman 将一个单元文件输出到控制台,可将此文件放入用户单元 systemd 目录(~/.config/systemd/user/
或 /etc/systemd/user/
)或系统单元 systemd 目录 (/etc/systemd/systtem
) 中,它可以通过 systemd 控制容器。--new
标志指示 Podman 在重启动时重新创建容器。这可以确保 systemd 单元是自给性的,而不依赖于外部状态。--name
标志可用于为容器指派一个用户友好的名称:如果不指定此标志,Podman 将使用容器 ID 而不是其名称。
要将容器作为用户单元进行控制,请执行以下命令:
❯ podman generate systemd --name --new --files web /home/user/container-web.service ❯ mv container-web.service ~/.config/systemd/user/ ❯ systemctl --user daemon-reload
现在可以通过 systemctl --user start container-web
启动容器:
❯ systemctl --user start container-web ❯ systemctl --user is-active container-web.service active
运行 podman ps
命令以查看所有正在运行的容器的列表:
❯ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af92743971d2 docker.io/library/nginx:latest nginx -g daemon o... 15 minutes ago Up 15 minutes ago 0.0.0.0:8080->80/tcp web
通过 systemd 管理容器的好处之一是能够在容器崩溃时自动重启动容器。可以通过将 SIGKILL
发送到容器中的主进程来模拟崩溃:
❯ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4c89582fa9cb docker.io/library/nginx:latest nginx -g daemon o... About a minute ago Up About a minute ago 0.0.0.0:8080->80/tcp web ❯ kill -9 $(podman inspect --format "{{.State.Pid}}" web) ❯ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0b5be4493251 docker.io/library/nginx:latest nginx -g daemon o... 4 seconds ago Up 4 seconds ago 0.0.0.0:8080->80/tcp web
请注意,如果容器是正常停止的(例如通过 podman stop web
),则容器不会重启动。要使容器始终可重启动,请将标志 --restart-policy=always
添加到 podman generate systemd
中。
13.3 更新容器映像 #
使用所述的方法意味着容器映像永远不会更新。可以通过将 --pull=always
标志添加到单元文件中的 ExecStart=
项来解决该问题。但请注意,这会增加容器的启动时间,并在每次重启动时更新映像。后一种行为还意味着,容器映像更新可能会因新造成的 bug 而导致容器在安排的维护时段之外不可用。
Podman 中的 auto-update
子命令提供了一种可行的解决方法。将标签 io.containers.autoupdate=registry
添加到容器,使 Podman 在运行 podman
auto-update
时从注册表中提取容器映像的新版本。这样,就可以在所需的时间使用一条命令更新所有容器映像,而且不会增加 systemd 单元的启动时间。
可以通过将行 --label
"io.containers.autoupdate=registry" \
添加到容器 systemd 单元文件的 ExecStart=
项来启用自动更新功能。对于 NGINX 示例,请如下所示修改 ~/.config/systemd/user/container-web.service
:
ExecStart=/usr/bin/podman run \ --cidfile=%t/%n.ctr-id \ --cgroups=no-conmon \ --rm \ --sdnotify=conmon \ --replace \ -d \ --name web \ --label "io.containers.autoupdate=registry" \ -p 8080:80 docker.io/nginx
重新装载守护程序并重启动容器后,执行更新试运行(此操作很可能不会报告任何更新):
❯ podman auto-update --dry-run UNIT CONTAINER IMAGE POLICY UPDATED container-web.service 87d263489307 (web) docker.io/nginx registry false
最好进行外部测试,以确保映像更新在一般情况下可以安全部署。如果您对我们的容器映像的质量有信心,可以通过启用 podman-auto-update.timer
来让 Podman 自动定期应用映像更新:
# just for the current user ❯ systemctl --user enable podman-auto-update.timer Created symlink /home/user/.config/systemd/user/timers.target.wants/podman-auto-update.timer → /usr/lib/systemd/user/podman-auto-update.timer. # or as root ❯ sudo systemctl enable podman-auto-update.timer Created symlink /etc/systemd/system/timers.target.wants/podman-auto-update.timer → /usr/lib/systemd/system/podman-auto-update.timer.
13.4 管理多个容器 #
某些应用程序需要依赖于多个容器才能正常运行,例如 Web 前端、后端服务器和数据库。Docker compose 是在一台计算机上部署多容器应用程序的流行工具。虽然 Podman 并不原生支持 compose
命令,但在大多数情况下,可以将 compose 文件移植到某个 Podman Pod 和多个容器。
以下示例在单个 Pod 中部署 Drupal 和 PostgreSQL 容器,并通过 systemd 单元管理这些容器。首先,创建一个公开 Drupal Web 界面的新 Pod:
❯ podman pod create -p 8080:80 --name drupal 736cab072c49e68ad368ba819e9117be13ef8fa048a2eb88736b5968b3a19a64
创建该 Pod 后,启动 Drupal 前端及其包含的 PostgreSQL 数据库:
❯ podman run -d --name drupal-frontend --pod drupal docker.io/drupal ffd2fbd6d445e63fb0c28abb8d25ced78f819211d3bce9d6174fe4912d89f0ca ❯ podman run -d --name drupal-pg --pod drupal \ -e POSTGRES_DB=drupal \ -e POSTGRES_USER=user \ -e POSTGRES_PASSWORD=pass \ docker.io/postgres:11 a4dc31b24000780d9ffd81a486d0d144c47c3adfbecf0f7effee24a00273fcde
这会生成三个正在运行的容器:Drupal Web 界面、PostgreSQL 数据库和 Pod 的基础架构容器。
❯ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2948fa1476c6 localhost/podman-pause:4.2.0-1660228937 2 minutes ago Up About a minute ago 0.0.0.0:8080->80/tcp 736cab072c49-infra ffd2fbd6d445 docker.io/library/drupal:latest apache2-foregroun... About a minute ago Up About a minute ago 0.0.0.0:8080->80/tcp drupal-frontend a4dc31b24000 docker.io/library/postgres:11 postgres 40 seconds ago Up 41 seconds ago 0.0.0.0:8080->80/tcp drupal-pg
为 Pod 创建 systemd 单元的方式类似于为单个容器创建此单元:
❯ podman generate systemd --name --new --files drupal /home/user/pod-drupal.service /home/user/container-drupal-frontend.service /home/user/container-drupal-pg.service ❯ mv *service ~/.config/systemd/user/ ❯ systemctl daemon-reload --user
由于 Podman 知道哪些容器属于 drupal
Pod 以及如何调用这些容器的 systemd 单元,因此它可以正确地将依赖项添加到 Pod 的单元文件中。这意味着,当您启动或停止 Pod 时,systemd 会确保该 Pod 中的所有容器自动启动或停止。
要检查 systemd 的依赖项处理,请先停止 drupal
Pod,然后校验主机上当前是否未运行任何容器:
❯ podman pod stop drupal 736cab072c49e68ad368ba819e9117be13ef8fa048a2eb88736b5968b3a19a64 ❯ podman pod rm drupal 736cab072c49e68ad368ba819e9117be13ef8fa048a2eb88736b5968b3a19a64 ❯ podman ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
通过 systemctl start --user pod-drupal.service
启动 drupal
Pod,systemd 会启动该 Pod 中的容器:
❯ systemctl start --user pod-drupal.service ❯ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d1589d3ac68b localhost/podman-pause:4.2.0-1660228937 5 seconds ago Up 5 seconds ago 0.0.0.0:8080->80/tcp ca41b505bd13-infra a49bea53c20c docker.io/library/postgres:11 postgres 4 seconds ago Up 5 seconds ago 0.0.0.0:8080->80/tcp drupal-pg dc9dca018dad docker.io/library/drupal:latest apache2-foregroun... 4 seconds ago Up 5 seconds ago 0.0.0.0:8080->80/tcp drupal-frontend
13.4.1 有关 Podman 的详细信息 #
如果您想要详细了解 Podman 并想要深入了解如何处理 Pod 部署,请查看 https://docs.podman.io/en/latest/ 和 https://github.com/containers/podman
13.5 包含 Kubernetes 的多容器主机 #
Kubernetes 是一个开源容器编制引擎,用于自动化容器化应用程序的部署、缩放和管理。该开源项目由云原生计算基金会 (CNCF) 主办。
凭借其多样化的特性和功能并受到大型开发者社区的支持,Kubernetes 已成为大多数容器即服务平台的首选标准。它提供广泛的且至关重要的功能来部署生产级的容器,其中包括高可用性、生命周期管理、存储、安全性和网络。
13.5.1 Kubernetes (k8s) #
使用 Kubernetes 可使多台计算机(或者服务器或节点)能够协同工作,并可以创建群集,然后您可以使用 API 来与此群集交互。有许多工具可用于部署 Kubernetes 群集,但 SUSE 建议使用 Rancher。使用 Rancher 不仅可以部署 Kubernetes 群集,而且还可以管理群集上运行的应用程序。此外,单个 Rancher 设置可以管理在裸机、本地或云服务提供商的任何位置运行的多个 Kubernetes 群集,使您可以更轻松地管理应用程序,同时减轻用于部署应用程序的设备的管理负担。
本指南不会介绍如何安装和使用 Rancher Kubernetes Engines (RKE),因为在 Rancher 的文档中可以找到详细说明。
13.5.2 轻量级 Kubernetes (k3s) #
K3s 是通过了 CNCF 认证的轻量级 Kubernetes 发行套件,由 Rancher 开发,其中内置了 IoT 和边缘计算功能。K3s 与 k8s 的不同之处在于,它是作为单个小于 60 MB 的二进制文件打包的,并已针对 ARM 进行优化。
我们强烈建议您阅读 Introduction to K3s,以及有关 how to install K3s and Rancher on SUSE Linux Enterprise Server 的文档