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) | ✅ 重启 |
关键说明
-
手动停止的优先级最高
任何策略下执行docker stop
都会阻止自动重启(包括always
和unless-stopped
)。 -
unless-stopped
的特殊性- ✅ 宿主机重启后自动启动:与
always
行为一致 - ❌ 手动停止后永不重启:即使宿主机重启也不会启动(区别于
always
)
- ✅ 宿主机重启后自动启动:与
-
on-failure
的细节- 仅当容器 非零退出码 时触发重启
- 支持可选参数
:max-retries
(如on-failure:3
)限制最大重试次数
-
守护进程/宿主机重启场景
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机制:
- Linux内核先尝试回收内存
- 若失败则触发OOM Killer杀死进程。
- 退出码=137(128 + 9(SIGKILL))
此时所有策略(always
/on-failure
/unless-stopped
)都会重启容器。但本质问题未解决,极有可能会形成死亡循环:
根治方案:容器内存限制(宿主机上的所有容器协调资源分配) + 调整JVM参数。