Docker 容器退出 0 后没有重启:on-failure 的触发条件
容器配置 on-failure 却停在 Exited (0),检查实际退出状态,按一次性任务或长期服务选择重启策略并保留人工停止语义。
容器配置了 --restart on-failure,进程结束后却停在 Exited (0)。先核对退出状态和策略是否符合任务目的:on-failure 根据非零退出码触发重启,正常退出 0 不满足这个条件;它也不是保证 daemon 重启后重新启动容器的策略。
本文针对 Docker Engine 的普通容器重启策略,不适用于 Swarm 服务、Kubernetes 工作负载或 systemd 本身的 Restart= 设置。
从实际容器状态判断
下面的容器名是示例:
docker inspect worker-app
docker logs --tail 100 worker-app
核对 HostConfig.RestartPolicy,以及 State 中的退出码、错误信息、完成时间和 OOM 状态。要看当前容器实际配置,不能只看一份尚未应用的启动脚本。
退出 0 只表示主进程报告正常结束,不证明后台任务完成,也不能证明所有子进程都健康。先检查入口脚本是否提前退出、是否丢掉应用失败状态,以及程序本来是不是一次性任务。容器里的其他线程曾在运行,并不会阻止主进程最终退出。
如果应用本应持续运行却正常退出,重启策略可以恢复进程,但不能解释这次退出原因。启动失败或 daemon 清理错误需要保留对应时间的日志,不要仅凭一次 Exited (0) 就认定 Docker 丢失了容器。
选择符合生命周期的策略
一次性初始化、迁移或批处理成功后应停止时,on-failure 可以只重试失败,但还要确保进程正确返回失败状态。有重试次数上限时,也要核对是否已经用完。
长期服务需要在进程退出后恢复,可以评估 always 或 unless-stopped。两者对人工停止后的行为不同:always 的人工停止状态会维持到 daemon 重启或手工启动;unless-stopped 会继续保留停止意图,即使 daemon 重启也不会因此自动拉起已停止的容器。
由负责部署的人确认策略后,可以修改指定容器,而不是批量修改所有容器。以下只是选择 unless-stopped 的示例:
docker update --restart unless-stopped worker-app
保存原策略及重试上限,并把最终选择同步到启动脚本或 Compose 配置,否则容器重新创建后可能恢复旧值。修改策略不等于已确认业务恢复;容器已经停止时,还应在允许任务执行的前提下按部署方式启动。
不要对本应只执行一次的写入任务设置无限自动重启。重复执行可能重复迁移、发送消息或写入数据,必须先确认幂等性和任务边界。
手工停止和健康状态要分开看
Docker 对人工停止后的自动重启有特殊处理,不能用 docker stop 的结果直接验证普通异常退出。健康检查变为 unhealthy 也不等于主进程退出,普通容器不会仅因这个状态就由重启策略自动重启。
如果日志显示停止超时后被强制终止,应继续检查应用关闭过程和停止时间。不能为了让 on-failure 生效而故意让每次关机都强制杀死进程,数据库和持久写入尤其需要正常关闭。
验收应覆盖实际需要的生命周期:服务启动正常、真正异常退出时按预定方式恢复、人工停止时符合运维意图,重新创建后策略仍正确。涉及主机重启的验证应安排维护窗口;回退时还原原策略与配置,不删除容器的数据卷。


