AlmaLinux 10:quadlet 到底把 .container 翻译成了什么
AlmaLinux 10.2 Server 组虚拟机,podman 5.8.2,quadlet 生成器 /usr/libexec/podman/quadlet 5.8.2。
实验网没有 registry 访问,所以镜像用 podman import 从本机 bash 与依赖库现场做了一个 6MB 左右的 localhost/labshell:1——这也顺带证明:quadlet 本身不依赖网络,只有 Image= 需要能被解析。
截图:public/evidence/quadlet/alma-quadlet.png。
起点:一份 .container
Section titled “起点:一份 .container”[Container]Image=localhost/labshell:1ContainerName=lab-webappPublishPort=8088:80Environment=LAB_ROLE=webAutoUpdate=registry
[Service]Restart=on-failureTimeoutStartSec=60
[Install]WantedBy=default.target文件名决定单元名:webapp.container → webapp.service。
生成器把它翻译成一条 podman run
Section titled “生成器把它翻译成一条 podman run”$ systemctl cat webapp.serviceWants=network-online.targetAfter=network-online.targetSourcePath=/etc/containers/systemd/webapp.containerRequiresMountsFor=%t/containers
ExecStart=/usr/bin/podman run --name lab-webapp --replace --rm \ --cgroups=split --sdnotify=conmon -d \ --label io.containers.autoupdate=registry \ --publish 8088:80 --env LAB_ROLE=web localhost/labshell:1逐段对照:
| 你写的 | 生成的 |
|---|---|
ContainerName=lab-webapp | --name lab-webapp |
PublishPort=8088:80 | --publish 8088:80 |
Environment=LAB_ROLE=web | --env LAB_ROLE=web |
AutoUpdate=registry | --label io.containers.autoupdate=registry |
[Service] Restart=on-failure | 单元的 Restart=on-failure |
| (隐式) | --replace --rm --cgroups=split --sdnotify=conmon -d |
--replace --rm 是理解生命周期的关键:同名容器会被替换,服务停止时容器随之删除。实测 systemctl stop 后 podman ps -a 计数为 0。
$ systemctl start webapp.service$ systemctl is-active webapp.serviceactive$ podman ps --format '{{.Names}} | {{.Status}} | {{.Ports}}'lab-webapp | Up 3 seconds | 0.0.0.0:8088->80/tcp$ ss -tlnp | grep 8088LISTEN 0 4096 0.0.0.0:8088 0.0.0.0:* users:(("conmon",pid=10981,fd=5))端口是 conmon 在监听——不是容器里的进程直接绑定,这也是为什么排障时要看 conmon。

AutoUpdate 不是一个开关
Section titled “AutoUpdate 不是一个开关”它只是往容器上打一个标签:
$ podman inspect lab-webapp --format '{{index .Config.Labels "io.containers.autoupdate"}}'registry真正执行更新的是 podman-auto-update.timer(或手动 podman auto-update)。也就是说:
- 写
AutoUpdate=registry不会自动拉新镜像; - 需要
systemctl enable --now podman-auto-update.timer; - 更新时容器必须由 podman 管理(有 label),且 registry 可达——离线环境里这条永远不生效。
开机自启与依赖
Section titled “开机自启与依赖”[Install]WantedBy=default.target不写 [Install] 就不会被 enable;写了之后 systemctl enable webapp.service 才有效。生成器还会自动加:
Wants=network-online.targetAfter=network-online.targetRequiresMountsFor=%t/containersnetwork-online.target 保证网络就绪再拉镜像;RequiresMountsFor 保证容器存储挂载完成。
- 改完
.container不daemon-reload:生成器不会重跑,改动完全不生效; - 改了
ContainerName但旧容器还在:--replace只在启动时生效,残留容器会占名字; systemctl restart之后容器重建:这是--rm的行为,别指望容器内数据留在容器层;- 以为
WantedBy=multi-user.target更「标准」:quadlet 场景下default.target才是推荐值。
练习:把一条 podman run 改成 quadlet
Section titled “练习:把一条 podman run 改成 quadlet”sudo podman run -d --name demo -p 8089:80 --env A=1 localhost/labshell:1sudo tee /etc/containers/systemd/demo.container >/dev/null <<'EOF'[Container]Image=localhost/labshell:1ContainerName=demoPublishPort=8089:80Environment=A=1[Install]WantedBy=default.targetEOFsudo systemctl daemon-reloadsudo systemctl start demo.servicesystemctl is-active demo.servicesudo podman ps --format '{{.Names}} {{.Ports}}'sudo systemctl stop demo.service检查:
- 手写的
podman run容器不会被 systemd 管理,先删掉避免同名冲突; systemctl cat demo.service能看到对应的podman run参数;- 启动后端口映射与
.container一致; - 停止后容器被删除。
常见问题
quadlet 和 podman-compose 怎么选?
单机少量服务用 quadlet(原生 systemd 依赖、开机自启、日志进 journal);compose 适合本地开发和多容器编排原型。
为什么我改了文件 systemctl 没反应?
quadlet 是 systemd 生成器,必须 daemon-reload 才重新生成单元。
容器日志在哪?
journalctl -u webapp.service;podman 把容器 stdout 接到 journald,除非你显式改 log driver。
- 容器基础:/containers/
- 日志与持久化:/journald-logging/
- 服务管理:/ops-monitoring/