使用 User= 或 --user 将无根容器作为 systemd 服务运行的最佳实践?

JK *_*iho 5 systemd non-root-user podman

我正在尝试使用 Podman 作为 systemd 服务运行无根容器。我还想以非 root 权限运行服务本身:

a) 作为系统服务,但User=设置为服务用户,或
b) 作为该服务用户的用户服务 ( systemd --user),之前已运行loginctl enable-linger <username>以允许长时间运行的服务。

这个想法是标准化我们未来在生产中进行小规模无守护程序和无根容器部署的方法,但我不完全确定选择这些方法中的哪一种,因为我不知道所有的陷阱。下面是一些背景讨论,其中实际问题以粗体显示。

作为初始实验,我正在运行图像maptiler/tileserver-gl以提供来自本地文件系统源的地图图块。

我注意到的一件事是,使用选项 a 时,单元文件内似乎没有内置方法来访问有关指定为的用户的任何信息(User=请参阅systemd.unit(5) 中的“说明符”;例如,%t点到/run,并%h指向/root)。tileserver-gl这是相关的,因为我最初为with创建了单元文件podman generate systemd --new--new在每次启动和停止时方便地创建和销毁容器,使用--cidfile=%t/%n.ctr-idinExecStart=来创建(和删除ExecStartPre=)包含容器 ID 的文件。当然,我们的服务用户没有写入权限/run。这不是破坏性的事情,因为我可以简单地进行硬编码/run/user/<uuid>%t或使用运行容器的非重新创建方法),但失去“活力”是一种耻辱。有没有办法User=从系统服务文件中获取用户的 UID 并将其插入到ExecStart=我错过的命令中?

如果我的理解是正确的,显然这两个选项都不能绑定到低于 1024 的 TCP 和 UDP 端口,而无需解决方法(这个看起来非常适合我们的情况)。我最初认为User=服务可以在放弃权限之前执行绑定,但显然情况并非如此。根据一些研究,最“systemd-native”的方式是使用套接字单元来实现这一点,但它似乎需要正在运行的服务主动支持它。这两个选项都不能“本地”绑定到没有套接字单元的 sub-1024 端口,甚至在使用这些端口时,也仅在某些情况下,这是否正确?

最终,我在这里寻找最佳实践。根据您阅读的来源,有些人强调--user登录会话期间的临时服务,但 OTOH 的存在enable-linger似乎表明对长时间运行的会话具有更广泛的适用性。您认为这两种选择有哪些显着的优缺点?对于这种“服务用户”案例,您认为哪种选择更好,为什么?

Eri*_*und 1

User=目前不支持使用 systemd 指令在 systemd 系统服务中运行无根 Podman 。

请参阅Podman GitHub 项目中的功能请求。

2023 年 11 月 21 日更新:

我想该功能仍然没有得到正式支持,但我使用User=test,Type=notify和创建了 systemd 系统服务Delegate=yes

[Unit]
Wants=network-online.target
After=network-online.target
Requires=user@1000.service
After=user@1000.service
RequiresMountsFor=/run/user/1000/containers

[Service]
User=test
Environment=PODMAN_SYSTEMD_UNIT=%n
KillMode=mixed
ExecStop=/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid
ExecStopPost=-/usr/bin/podman rm -f -i --cidfile=/run/user/1000/%N.cid
Delegate=yes
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
ExecStart=/usr/bin/podman run \
     --cidfile=/run/user/1000/%N.cid \
     --cgroups=split \
     --rm \
     --env "NGINX=3;" \
      -d \
     --replace \
     --name systemd-%N \
     --sdnotify=conmon \
     docker.io/library/nginx
Run Code Online (Sandbox Code Playgroud)

我尝试尽可能接近 Quadlet 生成的服务的样子。

测试网络服务器。似乎有效。

$ curl localhost:80 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Run Code Online (Sandbox Code Playgroud)

在示例中,我还使用了套接字单元来侦听特权端口。有关详细信息,请参阅 https://unix.stackexchange.com/a/762009/9360

我刚刚尝试过,所以我仍然需要弄清楚这个解决方案的效果如何。

参考:

示例 3 和示例 4: https: //github.com/eriksjolund/podman-nginx-socket-activation/