7.1 容器即系统服务:Quadlet 与单元生成


7.1 容器即系统服务:Quadlet 与单元生成

本节摘要:把容器交给 systemd 管理有两条路径:podman generate systemd 从现成容器反向生成服务单元(适合快速迁移存量),Quadlet 用声明式单元文件定义容器、由 systemd 原生接管(适合新部署)。本节完整演示两条路径,讲清 rootless 服务的 lingering 前提,并对比 Docker 时代"守护进程托管容器"的运维范式差异。

先看问题:没有 daemon,谁来拉起容器

把问题具体化。你在服务器上 podman run -d 了一个数据库容器,然后服务器重启了——容器不会回来。因为拉起它的那个会话没了,Podman 又没有常驻进程记得这件事。Docker 用户的直觉在这里会失灵:dockerd 加 --restart=always 让容器开机自启的整套机制,在无守护进程的世界里必须换一套实现。

正解是把容器声明为 systemd 服务。systemd 本来就是 Linux 的"进程总管":开机拉起、崩溃重启、依赖排序、日志收集全是它的本职。容器进程对它而言只是另一种被管理的进程——这个视角转换是本章一切内容的起点。

路径一:generate systemd,五分钟迁移存量容器

存量容器快速服务化,用生成器:

# 从现成容器生成服务单元(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,声明式的正解

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"都更接近系统层语义。

图:容器服务化的两条路径与 Docker 托管路径的对照

rootless 服务的暗门:lingering

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 时代做不到的混合编排。

本节要点回顾

  • 无 daemon 就把容器交给 systemd:拉起、重启、依赖排序全是 systemd 本职
  • generate 是快照,Quadlet 是声明:新部署一律推荐 Quadlet
  • Quadlet 是一族文件:container、pod、volume、network、kube 各司其职
  • lingering 是 rootless 服务的前提:注销后容器消失先查它
  • 范式收益:容器与本地服务进同一张依赖图,复用 systemd 成熟机制

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U