Quadlet 让 systemd 管理容器更容易

2024-09-20, 星期五, 17:46

培训DevOpsSystem Administration

需要部署一个应用容器做长期评估,执行 podman generate systemd …… 创建单元文件,提示:

DEPRECATED command: It is recommended to use Quadlets for running containers and pods under systemd.

Please refer to podman-systemd.unit(5) for details.

Quadlet 是 Podman 4.4 以来新增的帮助用户使用 systemd 管理容器的工具,相相较 podman generate systemd 隐藏了不少复杂细节。

首先需要一个 .container 单元文件描述需要哪个容器执行什么命令。以 rootless 身份使用 Quadlet 时,会在如下目录寻找单元文件(或这类文件的符号链接)。

  • $XDG_RUNTIME_DIR/containers/systemd/
  • $XDG_CONFIG_HOME/containers/systemd/$HOME/.config/containers/systemd/
  • /etc/containers/systemd/users/$UID
  • /etc/containers/systemd/users/

在本例中,笔者使用了一个符号链接:

mkdir -p $HOME/.config/containers/systemd/user/
touch $HOME/ContainerSpace/loki/loki.container
ln -s $HOME/ContainerSpace/loki/loki.container $HOME/.config/containers/systemd/user/

将 Grafana Loki 文档提供的 Docker 运行命令改写为 container 单元文件。

docker run --name loki -d -v $(pwd):/mnt/config -p 3100:3100 grafana/loki:3.0.0 -config.file=/mnt/config/loki-config.yaml

Docker 命令的参数可以按照 podman-systemd.unit - systemd units using Podman Quadlet 中的说明转换成 [Container] 配置。由于 Quadlet 和 Podman 还在快速迭代,如果提示什么参数不受支持,可以检查当前使用的 Podman 版本和网页右下角是否一致。

[Unit]
Description=Podman container-loki.service
Documentation=man:podman-systemd.unit
Wants=network-online.target
After=network-online.target

[Container]
Image=grafana/loki:3.0.0
PublishPort=3189:3100
Mount=type=bind,src=/home/yufan/ContainerSpace/loki/config,dst=/mnt/config,z
Exec=-config.file=/mnt/config/loki-config.yaml

[Install]
WantedBy=default.target

在系统启动或执行 systemctl daemon-reload 时,一个 systemd generator 会将其转换为服务单元,可以通过 systemctl start/status loki.service 启动服务或查看其状态。

> systemctl --user daemon-reload
> systemctl --user status loki.service

○ loki.service - Loki container
     Loaded: loaded (/home/yufan/.config/containers/systemd/loki.container; gen>
     Active: inactive (dead)
lines 1-3/3 (END)

> systemctl --user start loki.service

也可以使用 Quadlet 的 -dryrun 命令查看实际创建的服务单元:

> /usr/libexec/podman/quadlet -dryrun -user

quadlet-generator[3310]: Error occurred resolving path "/etc/containers/systemd/users": lstat /etc/containers/systemd/users: no such file or directory
quadlet-generator[3310]: Error occurred resolving path "/etc/containers/systemd/users/1002": lstat /etc/containers/systemd/users: no such file or directory
quadlet-generator[3310]: Loading source unit file /home/yufan/.config/containers/systemd/user/loki.container
---loki.service---
[Unit]
Description=Podman container-loki.service
Documentation=man:podman-systemd.unit
Wants=network-online.target
After=network-online.target
SourcePath=/home/yufan/.config/containers/systemd/user/loki.container
RequiresMountsFor=%t/containers
RequiresMountsFor=/home/yufan/ContainerSpace/loki/config

[X-Container]
Image=grafana/loki:3.0.0
PublishPort=3189:3100
Mount=type=bind,src=/home/yufan/ContainerSpace/loki/config,dst=/mnt/config,z
Exec=-config.file=/mnt/config/loki-config.yaml

[Install]
WantedBy=default.target

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
KillMode=mixed
ExecStop=/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
ExecStopPost=-/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
Delegate=yes
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
ExecStart=/usr/bin/podman run --name=systemd-%N --cidfile=%t/%N.cid --replace --rm --cgroups=split --sdnotify=conmon -d --publish 3189:3100 --mount type=bind,source=/home/yufan/ContainerSpace/loki/config,dst=/mnt/config,z grafana/loki:3.0.0 -config.file=/mnt/config/loki-config.yaml

尝试使用 systemctl --user enable --now loki.service 设置自启会收到 Unit is transient or generated 的错误消息,这是因为生成的文件通常没有持久的标识符,无法创建稳定的链接(也就是通常的 Install 方式)。不过由于 container 单元文件中声明了 [install] 配置,生成器会负责链接的动作,从某种角度上看,像是自动启用了 enable

Quadlet 还支持其他单元文件,例如:

  • .kube 要求 Quadlet 基于 Kubernetes 创建管理 pods 和容器的 systemd 服务单元
  • .network 创建可以被 .kube.container 使用的网络设备
  • .volume 创建可以供 .container 使用的卷