我创建了一台 Debian Bookworm 机器作为 LXC 容器管理器。我使用非特权 LXC 容器,该容器通过创建 systemd 用户范围的 lxc-unpriv-start 命令启动。我创建了一个服务,在服务器启动时启动我的容器,并在服务停止时启动干净的关闭。每个容器可能需要 2 到 3 分钟才能关闭。如果我手动停止主服务,一切都会正常。当我关闭服务器时出现问题,因为我的服务正确地等待容器终止,但与此同时 systemd-logind 杀死了所有用户会话,也残忍地杀死了我的容器。
我模拟创建一个只睡眠的 shell 的情况,并执行它
/usr/bin/systemd-run --user --scope -p "Delegate=yes" wait.sh &
并且在关机时被杀死。我该如何避免这种杀死?
答案1
Linger 应该可以解决这个问题。
从https://www.freedesktop.org/software/systemd/man/loginctl.html
为一个或多个用户启用/禁用用户逗留。如果为特定用户启用,则在启动时为用户生成用户管理器,并在注销后保留。这允许未登录的用户运行长时间运行的服务。以一个或多个用户名或数字 UID 作为参数。如果未指定参数,则为调用者会话的用户启用/禁用逗留。
loginctl enable-linger <username>
启用用户会话的停留功能将允许您的容器在您注销或系统关闭后继续运行。这应该可以防止 systemd-logind 强制终止用户会话和相关容器,让它们有机会正常关闭。
答案2
假设容器停止命令“阻塞”(即在容器停止后退出),您可能可以使用 systemd 用户服务运行容器启动命令,而不是直接从 shell 运行。假设您需要启动多个容器,您可以将服务模板写入 。服务$HOME/.config/systemd/user/
模板的文件名@
前面应该有.service
(例如[email protected]
)。
以下是一个例子:
[Unit]
PartOf=%i.scope
After=%i.scope
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/systemd-run --user --scope -u %i sh -c 'sleep 1d &'
ExecStop=/usr/bin/sleep 1m
如您所见,范围名称需要是“已知的”而不是生成的。
使用模板,您现在可以用例如启动容器systemctl --user start test@container-a
。您现在应该看到相应的范围一直保持到其“代理”服务停止(即命令ExecStop=
已退出)。
systemctl --user daemon-reload
当您对服务(模板)文件进行更改时,您可能需要运行。
PS 显然,如果您需要将额外的容器特定参数(与范围名称不是相同的字符串)传递给容器启动/停止命令,则可能必须编写多个服务文件,而不是使用模板。