本节摘要:把容器交给 systemd 管理有两条路径:podman generate systemd 从现成容器反向生成服务单元(适合快速迁移存量),Quadlet 用声明式单元文件定义容器、由 systemd 原生接管(适合新部署)。本节完整演示两条路径,讲清 rootless 服务的 lingering 前提,并对比 Docker 时代"守护进程托管容器"的运维范式差异。
把问题具体化。你在服务器上 podman run -d 了一个数据库容器,然后服务器重启了——容器不会回来。因为拉起它的那个会话没了,Podman 又没有常驻进程记得这件事。Docker 用户的直觉在这里会失灵:dockerd 加 --restart=always 让容器开机自启的整套机制,在无守护进程的世界里必须换一套实现。
正解是把容器声明为 systemd 服务。systemd 本来就是 Linux 的"进程总管":开机拉起、崩溃重启、依赖排序、日志收集全是它的本职。容器进程对它而言只是另一种被管理的进程——这个视角转换是本章一切内容的起点。
存量容器快速服务化,用生成器:
# 从现成容器生成服务单元(rootless) podman generate systemd --name --new --files mydb # /home/dev/mydb-container.service # 解读三个参数:--name 用容器名而非 ID 标识; # --new 每次启动重建容器(而不是复用旧的,幂等性更好); # --files 输出为文件 # 安装为用户级服务 mkdir -p ~/.config/systemd/user cp mydb-container.service ~/.config/systemd/user/ systemctl --user daemon-reload systemctl --user enable --now mydb-container.service # 验证:重启机器后容器自动回来了 systemctl --user status mydb-container.service # Active: active (running) ...
生成路径的关键限制:单元文件是"某个时刻容器配置的快照"。你后来改了容器参数,得重新生成、重新安装——配置漂移的风险回来了。这个限制直接引出了第二条路径。
Quadlet(Podman 4.4 起内置,systemd 单元生成器机制)把方向反过来:你直接写一个声明式单元文件,systemd 在启动时把它翻译成真正的服务单元。容器配置不再是从运行态"抽取"的快照,而是从一开始就是受版本管理的声明文件:
# 定义文件:~/.config/containers/systemd/web.container # [Unit] # Description=静态站点容器 # # [Container] # Image=docker.io/library/nginx:1.27-alpine # PublishPort=8080:80 # Volume=%h/www:/usr/share/nginx/html:Z # AutoUpdate=registry # # [Service] # Restart=always # # [Install] # WantedBy=default.target # 启用(无需手动生成任何东西) systemctl --user daemon-reload systemctl --user start web.service # 注意:服务名是 web.service——Quadlet 从文件名推导, # [Container] 段的每一条都对应 podman run 的一个参数族
Quadlet 文件的优雅之处在于"一个文件就是一种负载":.container 定义容器,.pod 定义 Pod,.volume 定义卷,.network 定义网络,甚至 .kube 定义 play kube 负载(第 8 章接上)。它们可以互相引用,systemd 负责依赖排序——数据库容器先于应用容器启动这类需求,用单元间的 After 与 Requires 表达,比任何编排器的"depends_on"都更接近系统层语义。

rootless 容器跑成服务时有个必答题:用户注销后,用户级 systemd 实例会被回收,容器跟着消失。解法是 lingering(驻留)——让用户的 systemd 实例在无登录会话时也保持运行:
# 给用户开启驻留(一次性配置,需要管理员执行一次) sudo loginctl enable-linger dev loginctl show-user dev | grep Linger # Linger=yes # 此后 dev 的用户级服务(包括所有 Quadlet 容器) # 在开机即启动、注销后存活——与系统服务行为对齐
忘了这一步的症状很典型:服务在测试时一切正常(你登录着),当晚注销后全部消失,第二天百思不解。记住排障口诀:rootless 服务不稳,先查 linger。
背景:一台部署在机房的边缘服务器要跑三个容器:反向代理、应用、日志收集,要求断电恢复后自动全量拉起、开机顺序正确。操作:Quadlet 写三个 .container 文件,应用单元声明 Requires 加 After 指向代理单元与日志单元;三份文件进版本库;目标机上 git 拉取后 systemctl --user daemon-reload 加 enable --now;开启 linger。结果:模拟断电测试,重启后三个容器按依赖顺序回来,全程无人工介入。解读:整个部署里"容器技术"只占三个声明文件,其余全是标准 systemd 知识——运维团队不需要学新体系,这是无守护进程架构在运维侧的真正红利。变式:若该服务器还跑着非容器化的系统服务(如本地 DNS),容器服务可以直接声明对它们的依赖——容器与本地服务在同一套依赖图里,这是 Docker 时代做不到的混合编排。