如何自动更新 Podman 容器

更新软件是一种很好的做法,尤其是当您在新更新中获得新功能和/或增加安全性时。

在本文中,我将向您展示如何为 Podman 管理的容器启用自动更新。

出于演示目的,我将使用 caddy 图片来自 码头工人中心.

确定获取图像的来源

要使用容器镜像,Podman 需要从某个地方拉取该镜像。 这个“某处”被称为自动更新策略。

自动更新策略如下:

  • registry: 当自动更新策略设置为字符串时 registryPodman 将从远程注册表中提取图像,例如 码头工人中心码头.
  • local: 当自动更新策略设置为字符串时 local, Podman 将从本地构建的图像中获取图像。 当您是开发人员并希望在将本地更改推送到远程注册表之前测试本地更改时,此更新策略会派上用场。

✍?我正在运行一个无根容器. 如果您使用 根满容器 尽我所能,但我是一个人,可能已经错过了。

只需使用 sudo 当您遇到与权限相关的错误时(仅当您有一个完整的容器时)。

启用自动更新

现在您已经知道什么是“自动更新策略”,我们现在可以继续本教程。

为 Podman 管理的容器启用自动更新所需要做的就是添加以下标签:

io.containers.autoupdate=AUTO_UPDATE_POLICY

替换字符串 AUTO_UPDATE_POLICYregistry 或与 local 你可以走了!

“但是当 Podman 没有守护进程时,容器如何自动更新呢?”

系统集成

当我说“你只需要添加 io.containers.autoupdate 给你的容器贴上标签,”你看……我撒谎了。

需要自动更新的容器必须由 systemd 管理。 “你为什么要把系统塞进我的喉咙?” 好吧,因为 Podman 有一个无守护进程的架构。 并且需要以某种方式管理容器。

如果您希望容器在启动时自动启动,您已经在使用 systemd 来执行此操作。

在下面链接的文章中,我讨论了如何将 Podman 容器(无论是全根容器还是无根容器)与 systemd 集成(目的是在启动时自动启动它)。

无论如何,我将简要介绍如何使用 systemd 管理 Podman 容器。

步骤 0:创建容器

确保您有一个现有的容器。 容器是运行还是停止都没有关系。

您可以通过运行以下命令来检查您拥有的容器:

podman container list

对于本教程,我提取了 Caddy Server 的旧图像(版本 2.5.2-alpine) 并将其重命名为 alpine. 重命名此图像将有助于演示更新过程。 您可以自己检查它,因为标签的图像ID 2.5.2-alpinealpine 是一样的;)

使用此图像,我创建了一个名为 prathams-caddy.

下面是它在我电脑上的样子:

$ podman images
REPOSITORY               TAG           IMAGE ID      CREATED      SIZE
docker.io/library/caddy  2.5.2-alpine  d83af79bf9e2  2 weeks ago  45.5 MB
docker.io/library/caddy  alpine        d83af79bf9e2  2 weeks ago  45.5 MB

$ podman container list
CONTAINER ID  IMAGE                   COMMAND               CREATED        STATUS            PORTS       NAMES
99d1838dd999  localhost/caddy:alpine  caddy run --confi...  5 seconds ago  Up 6 seconds ago              prathams-caddy

如您所见,我有一个名为 prathams-caddy 它正在运行 caddy 图像(这是旧版本)。

容器 prathams-caddy 是用标签创建的 io.containers.autoupdate 调成 registry. 如果您有一个没有此标签的现有容器,请不要担心; 你不需要重新创建你的容器。 这将在下一步中介绍。

第 1 步:为您的容器生成 systemd 服务文件

好吧,要通过 systemd 管理你的 Podman 容器,它需要变成一个服务。 实际上,您希望您的容器在启动时启动,并希望在您关闭系统时停止它。 将容器作为 systemd 服务运行是有意义的。

“但是为我拥有的每个容器编写一个 systemd 服务文件是不是工作量太大了?” 这是。 Podman 的开发人员已经想到了这一点。 您需要做的唯一手动工作是为每个容器运行一个命令。

如果你有一个 根满容器 (具有 root 权限的容器),运行以下命令:

sudo podman generate systemd -f --new --name CONTAINER_NAME

如果您的容器是 无根容器 (没有 root 权限的容器),运行以下命令:

podman generate systemd -f --new --name CONTAINER_NAME

替换字符串 CONTAINER_NAME 带有您的容器的名称和带有该名称的文件 container-CONTAINER_NAME.service 将被创建。

对于我的 Caddy Server 容器,我将执行以下操作:

$ podman generate systemd -f --new --name prathams-caddy
/home/pratham/container-prathams-caddy.service

从输出中可以看出,文件 container-prathams-caddy.service 被创建。 它将在当前工作目录中创建。

但这适用于已经为标签设置了值的容器 io.containers.autoupdate. 没有这个标签的已经存在的容器怎么办? 您不必使用此标签重新创建容器。

在这种情况下,编辑 systemd 服务文件并将以下行添加到 ExecStart 像这样的字段:

[...]
ExecStart=/usr/bin/podman run 
    [...]
    --label io.containers.autoupdate=registry
[...]

本质上,您的 systemd 服务文件只是调用 podman run 命令。 您所做的只是添加标签 io.containers.autoupdatepodman run 命令。 整洁的?

步骤 2:移动 systemd 服务文件

现在已经为我们创建了一个 systemd 服务,我们需要启用它。 但在启用之前,需要将服务文件移动到以下目录之一:

  • /etc/systemd/system/: 如果容器是 root-full 并且需要以超级用户权限启动。
  • ~/.config/systemd/user/:如果容器是无根的,请将其放在打算启动它的用户的相应目录中。

容器 prathams-caddy 是一个无根容器,所以我会相应地移动它。

$ mv -v container-prathams-caddy.service ~/.config/systemd/user/
renamed 'container-prathams-caddy.service' -> '/home/pratham/.config/systemd/user/container-prathams-caddy.service'

步骤 3:启用 systemd 服务

现在服务文件已放置在适当的目录中,我们可以继续启用它。 但首先,systemd 需要在不重新启动计算机的情况下了解我们新创建的服务。

如果服务需要超级用户权限,请使用以下命令重新加载 systemd:

sudo systemctl daemon-reload

如果服务正在启动无根容器,请运行以下命令:

systemctl --user daemon-reload

完成后,我们可以简单地使用 systemctl enable 命令来启用我们的服务。 根据您的要求使用任一命令:

# for a root-full container
sudo systemctl enable SERVICE_NAME.service

# for a root-less container
systemctl --user enable SERVICE_NAME.service

启用后,您可以检查服务的状态。 如果它说,不要惊慌 inactive (dead). 这是因为我们的服务是在启动时启动的,而我们在启用该服务后还没有启动计算机。

$ systemctl --user enable container-prathams-caddy.service
Created symlink /home/pratham/.config/systemd/user/default.target.wants/container-prathams-caddy.service → /home/pratham/.config/systemd/user/container-prathams-caddy.service.

$ systemctl --user status container-prathams-caddy.service
○ container-prathams-caddy.service - Podman container-prathams-caddy.service
     Loaded: loaded (/home/pratham/.config/systemd/user/container-prathams-caddy.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:podman-generate-systemd(1)

现在是停止容器(如果它正在运行)和 podman container rm 它并重新启动。

$ podman stop prathams-caddy
prathams-caddy

$ podman container rm prathams-caddy
99d1838dd9990b2f79b4f2c83bc9bc16dfbaf3fdeeb6c6418ddd6e641535ce21

第 4 步(可选):启用用户逗留

如果您为无根容器创建了 systemd 服务,最好为您的特定用户启用用户逗留。

这可以通过运行以下命令来实现:

sudo loginctl enable-linger

那么我的容器现在会自动更新吗?

“我添加了 io.containers.autoupdate 在我的容器上贴上标签。 我现在也用 systemd 管理我的容器。 我的容器现在会自动更新图像吗?”

好吧,不……但只剩下一步……这应该很重要,对吧? 正确的? 正确的…?

现在需要做的就是启用 podman-auto-update 服务。 使用以下命令执行此操作:

sudo systemctl enable podman-auto-update.service

随着 podman-auto-update 启用服务后,systemd 将检查是否需要更新任何图像。 如果有更新,则首先获取图像。 然后容器重新启动。 保留旧映像以防因多种原因需要回滚更新。

自动更新? 不,谢谢。

如果您不喜欢自动更新,您可能也很高兴知道您可以使用一个命令手动更新容器,前提是它们由 systemd 管理。

该命令是 podman auto-update 命令。 如果您只想检查更新,请传入 --dry-run 选项,以便实际上没有升级任何容器。

让我们看看我是否可以升级我的 caddy 图像从 ‘2.5.2-alpine’ 到 ‘2.6.1-alpine’ 使用 podman auto-update 命令。

$ podman container list
CONTAINER ID  IMAGE                   COMMAND               CREATED        STATUS            PORTS       NAMES
a712a3c8846b  docker.io/library/caddy:alpine  caddy run --confi...  2 seconds ago  Up 2 seconds ago              prathams-caddy

$ podman auto-update --dry-run
UNIT                              CONTAINER                      IMAGE         POLICY      UPDATED
container-prathams-caddy.service  a712a3c8846b (prathams-caddy)  caddy:alpine  registry    pending

正如你在 UPDATED 的输出列 podman auto-update 命令,它说 pending. 这表明有可用的更新。

要更新容器,请删除 --dry-run 选项。

结论

为您的 Podman 容器启用自动更新的过程可能会让人觉得有点牵强,但相信我,从长远来看,这将得到回报。 您管理的所有容器将在午夜自动更新(如果有任何更新)。 而且,如果容器遇到任何问题,systemd 会将其回滚到旧映像,因此您的容器会继续运行。

如果您觉得这很有用,请在下方评论并告诉我们您的想法! <3