【免费下载链接】podman
Podman: A tool for managing OCI containers and pods.
本文基于 Podman 官方选项文档 docs/source/markdown/options/restart.md,系统讲解 podman create、podman run、podman update、podman pod create 与 podman pod clone 共用的 --restart 选项:五种策略值的语义差异、on-failure 重试上限的写法与解析原理、podman kill/podman stop 对策略生效的例外情形,以及系统重启后如何借助 podman-restart.service 与 systemd 原生 Restart= 指令实现可靠的进程守护。读完本文,你将能根据业务场景精确选型重启策略,并能在 systemd 环境中正确配置容器自愈方案。
一、选项概览:一个选项,五个命令共用
--restart 是 Podman 中典型的"多命令共享选项",它被定义在一个共享选项文件中,并在以下命令中生效:
podman createpodman runpodman updatepodman pod createpodman pod clone
从命令行实现看,create 命令在构造容器配置时直接将 CLI 传入的策略写入底层配置(见 cmd/podman/containers/create.go 中 Restart: cliVals.Restart);而 update 命令会在运行时重新解析并校验该值,动态修改已存在容器的重启策略(见 cmd/podman/containers/update.go)。这意味着重启策略既可以在容器创建时固化,也可以在容器运行期间随时调整,无需重建容器。
二、五种策略值详解
--restart 接受一个 policy 参数,Podman 官方文档定义了以下合法取值:
| 策略值 | 行为说明 |
|---|---|
no | 容器退出后不重启(默认行为) |
never | no 的同义词,同样不重启 |
on-failure[:max_retries] | 仅当容器以非零退出码退出时重启;默认无限重试,可指定可选的最大重试次数 |
always | 无论退出状态如何都重启,无限重试 |
unless-stopped | 容器退出时重启,除非用户显式停止过它;系统重启后,只有重启前未被用户显式停止的容器才会被 podman-restart.service 拉起 |
在源码层面,这些取值被定义为常量,位于 libpod/define/container.go:
RestartPolicyNo = "no"RestartPolicyAlways = "always"RestartPolicyOnFailure = "on-failure"RestartPolicyUnlessStopped = "unless-stopped"RestartPolicyNone = ""(表示未请求任何策略,即默认状态)
同时该文件提供了 RestartPolicyMap(接受 none 作为 no 的另一种写法)和 ValidateRestartPolicy 校验函数,任何非法取值都会在参数解析阶段被拒绝,报出形如 "xyz" is not a valid restart policy 的错误。
2.1 no 与 never:默认不重启
no 是容器退出后的默认行为——什么都不做。never 是 no 的同义词,纯粹为了与 Docker 及部分编排工具的书写习惯保持一致。需要特别注意的是,ParseRestartPolicy 在解析时会对 never 做大小写不敏感(EqualFold)归一化处理,统一映射为 no 策略(见 pkg/util/utils.go)。
2.2 on-failure[:max_retries]:按退出码有选择地重启
on-failure 只在容器以非零退出码结束时触发重启,正常退出(退出码 0)的容器不会被拉起。该策略可以附带 :max_retries 后缀限制最大重试次数,例如:
# 非零退出时无限重启
podman run --restart=on-failure myapp
# 非零退出时最多重启 5 次,超过后放弃
podman run --restart=on-failure:5 myapp
从解析实现看,ParseRestartPolicy 使用 : 切分策略字符串:
- 仅一段(如
on-failure)表示不指定重试次数,即无限重试; - 两段(如
on-failure:5)时,第一段必须是on-failure,否则报错restart policy retries can only be specified with on-failure restart policy;第二段会被strconv.Atoi转为整数,负数直接拒绝,最终以uint形式存入容器的MaximumRetryCount; - 超过两段(含多个冒号)会被拒绝,错误信息为
invalid restart policy: may specify retries at most once。
2.3 always:无条件无限重启
只要容器退出,无论退出码是 0 还是非 0、无论退出原因是什么,Podman 都会把它重新拉起并无限重试。适用于需要"永远在线"的服务型容器。注意 always 不接受重试次数后缀——重试次数只能与 on-failure 搭配使用。
2.4 unless-stopped:尊重用户显式停止
unless-stopped 与 always 的行为几乎一致,唯一的差异体现在"用户是否显式停止过容器"这一点上:
- 容器退出(崩溃、被杀)→ 自动重启;
- 用户通过
podman stop/podman kill显式停止 → 不再自动重启; - 系统重启(reboot)后 → 重启前未被用户显式停止的容器会被
podman-restart.service自动拉起,而已被显式停止的容器保持停止状态。
这一点在 libpod/define/container.go 的注释中也有印证:unless-stopped 在"用户停止"维度上与 always 区分,前者尊重用户意图,后者则无条件重启。
三、关键例外:podman kill 与 podman stop 的优先权
官方文档明确强调了一条重要规则:
Restart policy does not take effect if a container is stopped via the podman kill or podman stop commands.
也就是说,无论容器配置的是 always 还是 unless-stopped,只要用户使用 podman stop(优雅停止)或 podman kill(直接发信号终止)显式结束容器,重启策略都不会生效,容器保持停止状态。这一设计保证了运维人员的"停止"指令永远不会被自动重启机制"顶回去"。
在容器状态模型中,该判定结果被记录为 RestartPolicyMatch 字段(见 libpod/container.go),用于在退出流程中决定是否触发重启逻辑。
四、系统重启后的自动恢复:podman-restart.service
容器重启策略只在"容器进程退出"这个事件层面生效,并不包含"系统(宿主机)重启"场景。为了解决这个问题,Podman 专门提供了一个 systemd 单元文件 podman-restart.service:
- 它在系统启动(开机)后被触发执行;
- 扫描所有配置了
always或unless-stopped策略的容器; always:无条件重启所有相关容器;unless-stopped:仅重启那些在重启前没有被用户显式停止过的容器(若用户在重启前执行过podman stop,则该容器在开机后保持停止)。
因此,要让容器在宿主机重启后依然自动恢复,必须确保 podman-restart.service 处于启用状态,并正确使用上述两种策略。需要留意的是,源码注释中明确说明 unless-stopped 与 always 在"系统重启"维度上的完整语义是 Podman 持续演进的方向(见 libpod/define/container.go),部署时建议以当前版本的实际行为为准验证。
五、与 systemd 集成:优先使用 Restart= 而非 --restart
官方文档给出了一条明确的架构性建议:
When running containers in systemd services, use the restart functionality provided by systemd. In other words, do not use this option in a container unit, instead set the
Restart=systemd directive in the[Service]section.
也就是说,当容器由 systemd 管理(例如通过 podman generate systemd 生成的单元文件,或手工编写的容器单元)时,不要在容器本身设置 --restart 策略,而应在 systemd 单元文件的 [Service] 段中设置:
[Service]
Restart=always
RestartSec=10
原因在于:systemd 本身就是宿主机上成熟的进程监督器,自带 Restart=、RestartSec=、StartLimitIntervalSec= 等完整的重启与限流语义。把重启职责交给 systemd,可以避免"容器内策略与单元文件策略双重管理、行为冲突"的问题。相关背景可进一步参考 podman-systemd.unit(5) 与 systemd.service(5) 手册页(仓库内对应文档位于 docs/source/markdown)。
六、实战示例:从创建到动态调整
6.1 创建时指定策略
# 服务型容器:退出即重启,无限重试
podman run -d --name web --restart=always nginx
# 任务型容器:仅失败时重启,最多 3 次
podman run -d --name worker --restart=on-failure:3 my-worker-image
# 尊重用户停止意图
podman run -d --name db --restart=unless-stopped postgres
# 显式不重启(默认)
podman run -d --name job --restart=no my-job-image
6.2 运行时调整策略
容器创建后无需重建即可修改策略:
# 将已有容器的策略改为 always
podman update --restart=always web
# 改为失败时重启、最多 5 次
podman update --restart=on-failure:5 worker
update 命令在解析阶段复用了同一套 ParseRestartPolicy 校验逻辑(见 cmd/podman/containers/update.go),因此非法策略、在非 on-failure 上携带重试次数等错误会在命令执行时被立即拦截。
6.3 查看当前策略
通过 podman inspect 可以读取容器当前的重启策略与重试上限。其数据结构定义在 libpod/define/container_inspect.go:
Name:策略名,允许值为""或no(不动作)、on-failure(非零退出码时重启,可带最大重试次数)、always(总是重启,除非 API 显式请求停止);MaximumRetryCount:on-failure策略下的最大重试次数,其他策略下不使用。
podman inspect web --format '{{.HostConfig.RestartPolicy.Name}}'
podman inspect web --format '{{.HostConfig.RestartPolicy.MaximumRetryCount}}'
七、常见误用与注意事项
- 重试次数只属于
on-failure:always:3、unless-stopped:2这类写法会被解析器直接拒绝,报错信息会提示重试次数只能与on-failure搭配。 kill/stop永远优先:即使配置了always,podman stop后容器也不会复活,这是刻意设计的运维安全网。- 系统重启不等于进程退出:仅靠
--restart无法覆盖宿主机重启场景,必须配合podman-restart.service;同时在 systemd 环境下应放弃容器内策略,改用单元文件的Restart=指令,避免双重管理冲突。 - pod 内容器的约束:容器位于 pod 中时,重启策略的适用与 pod 生命周期管理相互关联,
create命令源码中对此场景有专门注释提醒(见 cmd/podman/containers/create.go),使用pod create/pod clone时请结合 pod 的--restart语义一并规划。
八、小结
Podman 的 --restart 选项通过五种策略值覆盖了"不重启、按退出码重启、无条件重启、尊重用户停止"的完整需求矩阵,并借助 podman-restart.service 将恢复能力延伸到系统重启场景。选择策略时只需把握三条主线:进程级崩溃由策略值决定、运维级停止永远高于策略、系统级重启交给 systemd 单元。在 systemd 托管环境下,让 systemd 的 Restart= 承担守护职责,Podman 的策略则专注于裸容器运行场景,二者各司其职,即可构建清晰、可预期的容器自愈体系。
【免费下载链接】podman
Podman: A tool for managing OCI containers and pods.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



