Rocky Linux 9.4下创建最小Podman系统服务的问题排查
问题场景
在Rocky Linux 9.4上创建了以普通用户运行的Podman系统服务,服务单元文件/etc/systemd/system/echo.service内容如下:
[Unit] Description=Test Echo service After=network.target [Service] User=<local user> ExecStart=/usr/bin/podman run -t --name echo-podman alpine:latest sh -c "while true; do echo 'Hello, World!'; sleep 1; done" ExecStop=/usr/bin/podman stop echo-podman -t 10 ExecStopPost=/usr/bin/podman rm -f echo-podman TimeoutStartSec=0 Restart=on-failure StartLimitBurst=3 RestartSec=10s [Install] WantedBy=multi-user.target
执行启动命令:
sudo systemctl enable echo sudo systemctl start echo
遇到两个核心问题:
- 服务运行正常,但journald无法捕获容器的输出内容
- 重启服务耗时约10秒,
podman stop无法快速中断容器内的循环脚本
相关日志:
sudo journalctl -u echo -f Sep 03 09:50:56 <host> systemd[1]: Started Test Echo service. <Output missing here> Sep 03 09:51:31 <host> systemd[1]: Stopping Test Echo service... Sep 03 09:51:41 <host> systemd[1]: echo.service: Main process exited, code=exited, status=143/n/a Sep 03 09:51:41 <host> systemd[1]: echo.service: Failed with result 'exit-code'. Sep 03 09:51:41 <host> systemd[1]: Stopped Test Echo service.
问题1:journald无法捕获容器输出的解决方法
非特权用户运行Podman时,容器输出默认不会被systemd收集,可通过以下两种方式修复:
方式1:修改Podman运行参数,直接对接journald
移除-t参数(伪终端分配会干扰systemd的输出捕获),添加--log-driver=journald让容器日志直接写入journald:
ExecStart=/usr/bin/podman run --name echo-podman --log-driver=journald alpine:latest sh -c "while true; do echo 'Hello, World!'; sleep 1; done"
修改后,journalctl -u echo -f即可实时看到容器的输出内容。
方式2:配置systemd强制捕获输出
在[Service]段添加以下配置,强制systemd收集服务的标准输出和错误:
[Service] User=<local user> StandardOutput=journal+console StandardError=journal+console # 其他原有配置保留
该方式无需修改Podman启动参数,同样能让journald捕获到容器输出。
问题2:podman stop无法快速中断循环的解决方法
容器内的while循环脚本默认不响应SIGTERM信号(sleep命令会忽略该信号),导致podman stop需等待超时才会强制终止容器,可通过以下方式优化:
方式1:让脚本响应SIGTERM信号
修改容器内的脚本,添加信号捕获逻辑,收到SIGTERM时立即退出循环:
sh -c "trap 'exit 0' TERM; while true; do echo 'Hello, World!'; sleep 1; done"
此时podman stop发送SIGTERM后,脚本会立即终止,容器也会快速停止,无需等待超时。
方式2:修改ExecStop强制杀容器(不推荐)
若不想修改脚本,可将ExecStop改为直接发送SIGKILL强制终止容器:
ExecStop=/usr/bin/podman kill echo-podman
该方式虽能快速停止容器,但属于暴力终止,可能引发数据丢失风险(本场景无数据风险),建议优先使用方式1。
最终优化后的服务单元文件
整合上述两种问题的解决方案,最终的echo.service内容如下:
[Unit] Description=Test Echo service After=network.target [Service] User=<local user> StandardOutput=journal+console StandardError=journal+console ExecStart=/usr/bin/podman run --name echo-podman alpine:latest sh -c "trap 'exit 0' TERM; while true; do echo 'Hello, World!'; sleep 1; done" ExecStop=/usr/bin/podman stop echo-podman -t 2 ExecStopPost=/usr/bin/podman rm -f echo-podman TimeoutStartSec=0 Restart=on-failure StartLimitBurst=3 RestartSec=10s [Install] WantedBy=multi-user.target
这里将ExecStop的超时时间缩短至2秒,进一步降低极端情况下的等待时长。
内容的提问来源于stack exchange,提问作者bgp2000

