跳转到内容
搜索 AlmaLinux 文档

    浏览当前文档目录

    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。

    /etc/containers/systemd/webapp.container
    [Container]
    Image=localhost/labshell:1
    ContainerName=lab-webapp
    PublishPort=8088:80
    Environment=LAB_ROLE=web
    AutoUpdate=registry
    [Service]
    Restart=on-failure
    TimeoutStartSec=60
    [Install]
    WantedBy=default.target

    文件名决定单元名:webapp.container → webapp.service。

    $ systemctl cat webapp.service
    Wants=network-online.target
    After=network-online.target
    SourcePath=/etc/containers/systemd/webapp.container
    RequiresMountsFor=%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.service
    active
    $ podman ps --format '{{.Names}} | {{.Status}} | {{.Ports}}'
    lab-webapp | Up 3 seconds | 0.0.0.0:8088->80/tcp
    $ ss -tlnp | grep 8088
    LISTEN 0 4096 0.0.0.0:8088 0.0.0.0:* users:(("conmon",pid=10981,fd=5))

    端口是 conmon 在监听——不是容器里的进程直接绑定,这也是为什么排障时要看 conmon。

    AlmaLinux 10.2:quadlet 源文件、生成单元与运行结果同屏

    它只是往容器上打一个标签:

    $ 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 可达——离线环境里这条永远不生效。
    [Install]
    WantedBy=default.target

    不写 [Install] 就不会被 enable;写了之后 systemctl enable webapp.service 才有效。生成器还会自动加:

    Wants=network-online.target
    After=network-online.target
    RequiresMountsFor=%t/containers

    network-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”
    Terminal window
    sudo podman run -d --name demo -p 8089:80 --env A=1 localhost/labshell:1
    sudo tee /etc/containers/systemd/demo.container >/dev/null <<'EOF'
    [Container]
    Image=localhost/labshell:1
    ContainerName=demo
    PublishPort=8089:80
    Environment=A=1
    [Install]
    WantedBy=default.target
    EOF
    sudo systemctl daemon-reload
    sudo systemctl start demo.service
    systemctl is-active demo.service
    sudo podman ps --format '{{.Names}} {{.Ports}}'
    sudo systemctl stop demo.service

    检查:

    1. 手写的 podman run 容器不会被 systemd 管理,先删掉避免同名冲突;
    2. systemctl cat demo.service 能看到对应的 podman run 参数;
    3. 启动后端口映射与 .container 一致;
    4. 停止后容器被删除。

    常见问题

    quadlet 和 podman-compose 怎么选?

    单机少量服务用 quadlet(原生 systemd 依赖、开机自启、日志进 journal);compose 适合本地开发和多容器编排原型。

    为什么我改了文件 systemctl 没反应?

    quadlet 是 systemd 生成器,必须 daemon-reload 才重新生成单元。

    容器日志在哪?

    journalctl -u webapp.service;podman 把容器 stdout 接到 journald,除非你显式改 log driver。