容器异常恢复:Docker restart策略特性对比

1 Docker 容器 Restart 策略对比表

下面是 Docker 容器 --restart 策略的触发时机对比表,清晰展示了不同策略在常见场景下的行为:

触发场景--restart always--restart on-failure[:max-retries]--restart unless-stopped
容器正常退出
(exit code = 0)
✅ 重启❌ 不重启✅ 重启
容器异常退出
(exit code ≠ 0)
✅ 重启✅ 重启
(可配重试次数)
✅ 重启
手动(强制)停止容器
docker stop/kill
❌ 不重启❌ 不重启❌ 不重启
Docker 守护进程重启/宿主机系统重启
(容器原本在运行)
✅ 重启❌ 不重启✅ 重启
Docker 守护进程重启/宿主机系统重启
(容器之前被手动停止)
✅ 重启❌ 不重启❌ 不重启(尊重手动停止操作)
OOM 被系统杀死✅ 重启✅ 重启
(exit code ≠ 0)
✅ 重启

关键说明

  1. 手动停止的优先级最高
    任何策略下执行 docker stop 都会阻止自动重启(包括 alwaysunless-stopped)。

  2. unless-stopped 的特殊性

    • 宿主机重启后自动启动:与 always 行为一致
    • 手动停止后永不重启:即使宿主机重启也不会启动(区别于 always
  3. on-failure 的细节

    • 仅当容器 非零退出码 时触发重启
    • 支持可选参数 :max-retries(如 on-failure:3)限制最大重试次数
  4. 守护进程/宿主机重启场景
    on-failure 不会因守护进程或宿主机重启而触发容器启动,除非容器之前因失败退出且满足重启条件。

2 使用建议

  • 生产服务 ​: unless-stopped 平衡自动恢复与人工控制。它兼顾了高可用(异常时自动重启)和可管理性(尊重管理员的手动停止操作)。适用于绝大多数需要长时间运行的后台服务(Web 服务器、数据库、消息队列等)。
  • 按需任务 ​: 选 on-failure 确保失败后重试。适用于那些期望持续运行,但可能会遇到临时性错误的服务。它允许容器在完成预期工作后正常停止(例如批处理任务),并且在出现问题时自动恢复。限制重启次数可以防止故障应用耗尽资源。
  • ​关键服务 ​​​:需无条件持续运行时选 always。必须 100% 持续运行的服务(如核心 API)。 需要注意的是,之前手工停止的容器在docker守护进程重启或宿主机系统重启后会自动重启。这个可能会引发一些未预期的行为,比如某些已下线的系统在系统重启之后重新上线了,引发安全事件。
  • ​​临时任务 ​​:保持默认 no或显式指定 --restart=no。

3 健康检查 ≠ 重启策略

许多同学误以为HEALTHCHECK指令能触发重启。实际上:

HEALTHCHECK --interval=30s CMD curl -f http://localhost:8080/actuator/health

即使健康检查失败,只要PID 1进程还在运行,Docker就不会重启容器!需配合监控系统实现高级故障转移。

4 反思:重启策略是银弹吗?

通过深度拆解restart参数,我们发现:

  • 优势:快速恢复瞬时故障(如偶发OOM)
  • ⚠️ 局限:掩盖资源瓶颈问题(比如内存泄露)

重启策略像"止疼药",缓解症状却未治病根

5 Linux OOM Killer的"黑盒效应"

当容器内存超限时,会触发linux oom killer机制:

  1. Linux内核先尝试回收内存
  2. 若失败则触发OOM Killer杀死进程。
  3. 退出码=137(128 + 9(SIGKILL))

此时所有策略(always/on-failure/unless-stopped)都会重启容器。但本质问题未解决,极有可能会形成死亡循环:

内存超限
OOM Killer杀进程
Docker重启容器

根治方案:容器内存限制(宿主机上的所有容器协调资源分配) + 调整JVM参数。