本文主要介绍 Docker 的容器重启策略(docker run --restart / Compose restart):各策略含义、退避行为、与 --rm 的互斥关系,以及运维上如何查看重启次数与适用场景。

内容整理自 Docker run reference:Restart policies,并结合常见部署习惯说明选用方式。具体行为以当前 Docker Engine 版本文档为准。

背景说明

容器进程退出后是否由 dockerd 拉起、守护进程重启后是否自动启动容器,由重启策略控制。策略写在容器配置里,可在 docker rundocker update 或 Compose/编排清单中声明。

策略生效时,docker ps 中容器状态多为 UpRestarting;也可用 docker events 观察重启事件。

策略一览

策略行为
no退出后不自动重启。默认值。
on-failure[:max-retries]仅在容器以非 0 状态退出时重启;可选限制最大重启次数。
always无论退出码如何都重启;且 dockerd 启动时会拉起该容器(不论之前是否被 stop,语义见下表对比)。
unless-stoppedalways 类似会自动重启,但若在 dockerd 停止前容器已被手动 stop,则 daemon 再启动时不会自动拉起。

说明(工程上常混用的点):

  • always:适合“机器重启后也要起来”的常驻服务;手动 docker stop 后,若再重启 Docker 服务,容器仍会被拉起。
  • unless-stopped:同样适合常驻服务,但尊重“我主动停过”的状态,维护窗口更直观。
  • on-failure:适合任务型/允许 0 正常退出的进程;成功退出(0)不会空转重启。
  • no:调试、一次性任务、或由 systemd/K8s 等上层负责生命周期时使用。

退避与成功判定

为避免重启风暴,daemon 在连续重启之间加入指数退避:从 100ms 起,每次加倍(100 → 200 → 400 → …),直到:

  • 命中 on-failure 的最大次数,或
  • 对容器执行了 docker stop / docker rm -f

若某次启动后容器持续运行至少约 10 秒,退避延迟会重置为 100ms。因此“起来又秒退”会拉长间隔,看起来像“重启变慢”,属于保护行为。

配置示例

docker run

# 总是重启
docker run -d --name redis --restart=always redis:latest

# 非 0 退出才重启,最多连续尝试 10 次
docker run -d --name redis --restart=on-failure:10 redis:latest

修改已有容器

docker update --restart=unless-stopped <container>

与 –rm 互斥

--restart--rm 不能同时使用。重启场景下容器实例要保留;--rm 则在退出时删除容器,语义冲突,daemon 会直接报错。

Compose 示意

services:
  app:
    image: <image>
    restart: unless-stopped

观测与验证

查看重启次数:

docker inspect -f '{{ .RestartCount }}' <container>

查看最近一次启动时间:

docker inspect -f '{{ .State.StartedAt }}' <container>

查看当前策略:

docker inspect -f '{{ .HostConfig.RestartPolicy.Name }} {{ .HostConfig.RestartPolicy.MaximumRetryCount }}' <container>

验证思路(按策略自测,勿在生产乱杀进程):

  1. always / unless-stopped 容器 docker stopdocker start,确认可手动拉起。
  2. 模拟非 0 退出(例如错误入口命令),观察 RestartCount 是否增加、on-failure:N 是否在 N 次后停止。
  3. 重启 Docker 服务后,对比 alwaysunless-stopped(后者在 stop 过的容器上不应自动 Up)。

示例输出中的数字与时间为文档常见示意,以本机 inspect 为准

# RestartCount 示例
2

# StartedAt 示例
2015-03-04T23:47:07.691840179Z

与 docker run 退出码的关系

docker run 前台退出码可帮助区分失败阶段(摘自官方说明):

退出码含义
125Docker daemon / 客户端自身错误(如非法 flag)
126容器内命令无法执行(权限等)
127容器内命令不存在
其它一般为容器内进程的退出码
docker run --foo busybox; echo $?
# 非法参数 → 常为 125

docker run busybox /bin/sh -c 'exit 3'; echo $?
# 进程 exit 3 → 输出 3

重启策略看的是容器退出后的守护行为,与上述前台 docker run 退出码 complementary:编排排障时两者都要看。

选用建议

场景更合适的策略
Web/Redis 等常驻服务,希望开机自启unless-stopped(常用)或 always
批处理,0 表示成功结束on-failureno
本地调试no
已由 Kubernetes/Systemd 管生命周期通常 no,避免双重拉起

Swarm/Compose/K8s 还有各自的重启与健康检查模型,不要假设与单机 --restart 完全一致。

注意事项

  • 应用自身应尽量可重入;依赖“重启凑活”会掩盖配置错误。
  • 连续崩溃时关注退避导致的间隔变长,结合日志查根因。
  • MaximumRetryCount 仅对 on-failure 有意义。
  • 文档链接与语义随 Docker 版本可能微调,升级 Engine 后核对官方 run reference。

参考资料