Podman `--restart` 重启策略详解:从容器退出行为到 systemd 集成实践

  • 容器运行时
  • 云原生
  • CLI

【免费下载链接】podman

Podman: A tool for managing OCI containers and pods.

项目地址: https://gitcode.com/gh_mirrors/po/podman
点击查看 免费下载

本文基于 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 create
  • podman run
  • podman update
  • podman pod create
  • podman pod clone

从命令行实现看,create 命令在构造容器配置时直接将 CLI 传入的策略写入底层配置(见 cmd/podman/containers/create.go 中 Restart: cliVals.Restart);而 update 命令会在运行时重新解析并校验该值,动态修改已存在容器的重启策略(见 cmd/podman/containers/update.go)。这意味着重启策略既可以在容器创建时固化,也可以在容器运行期间随时调整,无需重建容器。

二、五种策略值详解

--restart 接受一个 policy 参数,Podman 官方文档定义了以下合法取值:

策略值行为说明
no容器退出后不重启(默认行为)
neverno 的同义词,同样不重启
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}}'

七、常见误用与注意事项

  1. 重试次数只属于 on-failure:always:3、unless-stopped:2 这类写法会被解析器直接拒绝,报错信息会提示重试次数只能与 on-failure 搭配。
  2. kill/stop 永远优先:即使配置了 always,podman stop 后容器也不会复活,这是刻意设计的运维安全网。
  3. 系统重启不等于进程退出:仅靠 --restart 无法覆盖宿主机重启场景,必须配合 podman-restart.service;同时在 systemd 环境下应放弃容器内策略,改用单元文件的 Restart= 指令,避免双重管理冲突。
  4. 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 的策略则专注于裸容器运行场景,二者各司其职,即可构建清晰、可预期的容器自愈体系。

  • 容器运行时
  • 云原生
  • CLI

【免费下载链接】podman

Podman: A tool for managing OCI containers and pods.

项目地址: https://gitcode.com/gh_mirrors/po/podman
点击查看 免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值