跳到内容跳到页面导航:上一页 [access key p]/下一页 [access key n]
documentation.suse.com / 容器指南 / 容器编制
适用范围 容器指南

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 值和内核名称空间全都指派给基础架构容器。因此,以后无法更改这些值。

image

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
警告
警告

如果此命令显示以下警告,请参见Using container-suseconnect on non-SLE hosts or with Podman, Buildah, and nerdctl

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 的文档