Docker Compose 重启策略不生效?排查与正确配置指南
快速答案
- 核心结论:Docker Compose 重启策略不生效通常由三个原因导致:YAML 中
restart: no被解析为布尔值false、在非 Swarm 模式下使用了deploy.restart_policy、或容器运行时间不足 10 秒的“稳定窗口”。 - 第一检查项:确认你的
docker-compose.yml中restart属性写在顶层服务定义中(而非deploy下),且restart: no必须用引号包裹为restart: "no"。 - 最小修复命令:将
restart: no改为restart: "no",或根据需求使用restart: always/restart: unless-stopped,然后执行docker-compose up --detach --build重新部署。 - 适用环境:Docker Compose v2/v3 均支持顶层的
restart属性;deploy.restart_policy仅适用于 Docker Compose v3 的 Swarm 模式(docker stack deploy)。
它解决什么问题 / 适用场景
Docker Compose 的重启策略用于定义容器在退出或崩溃后的自动恢复行为。它适用于:
- 微服务架构:确保 API 服务、消息队列消费者等关键服务在异常退出后自动恢复。
- 后台任务处理系统:如定时任务、数据同步脚本,避免因单次失败导致服务永久停止。
- 开发环境:减少手动重启容器的操作,提升开发效率。
与 Kubernetes 的 restartPolicy 相比,Docker Compose 的重启策略更轻量,适合单机或小规模集群,无需额外的编排层。
核心配置 / 参数说明
以下参数均定义在 docker-compose.yml 的服务级别(顶层 restart)或 deploy 块下(Swarm 模式)。
顶层 restart 属性(普通模式)
| 参数值 | 行为描述 | 适用场景 |
|---|---|---|
"no" | 容器退出后不自动重启(默认行为) | 一次性任务、手动管理的服务 |
always | 无论退出码如何,总是重启容器;Docker 守护进程重启后也会重启 | Web 服务器、API 服务等需要持续运行的服务 |
unless-stopped | 总是重启,除非用户手动 docker stop 停止容器 | 数据库、有状态服务,避免意外重启 |
on-failure | 仅在容器以非零退出码退出时重启 | 批处理任务、数据迁移脚本 |
on-failure:5 | 同上,但最多尝试重启 5 次 | 需要限制重启次数的任务 |
Swarm 模式下的 deploy.restart_policy(仅 docker stack deploy 生效)
| 参数 | 说明 | 示例 |
|---|---|---|
condition | 重启条件:none、on-failure、any(默认) | condition: on-failure |
delay | 重启尝试之间的等待时间 | delay: 5s |
max_attempts | 最大重启尝试次数 | max_attempts: 3 |
window | 判断重启是否成功的窗口时间 | window: 120s |
重要:deploy.restart_policy 在普通 docker-compose up 中会被完全忽略,必须使用 docker stack deploy 部署到 Swarm 集群。
常见报错与排查
1. restart: no 被解析为布尔值 false
现象:容器退出后没有按预期不重启,或者重启策略完全失效。
根因:YAML 解析器将 no 视为布尔值 false,导致重启策略被设置为默认行为(即 restart: "no" 的等价效果),但实际行为可能因版本而异。
解决:始终使用引号包裹 "no":
YAMLservices: my-service: image: my-image restart: "no" # 必须用引号
2. 容器运行时间不足 10 秒
现象:容器启动后立即崩溃,但重启策略未生效,容器保持退出状态。
根因:Docker 的重启策略有一个 10 秒的“稳定窗口”——容器必须成功运行至少 10 秒后,重启策略才会被激活。如果容器在 10 秒内崩溃,Docker 认为这是启动失败,不会触发重启。
解决:
- 检查容器日志:
docker logs <container-name> - 修复导致崩溃的代码或配置(如环境变量缺失、端口冲突、依赖服务未就绪)
- 如果依赖其他服务,使用
depends_on并配合健康检查:
YAMLservices: app: image: my-app depends_on: db: condition: service_healthy db: image: postgres healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5
3. 在非 Swarm 模式下使用 deploy.restart_policy
现象:配置了 deploy.restart_policy,但容器崩溃后没有自动重启。
根因:deploy 块下的配置仅适用于 Docker Compose v3 的 Swarm 模式。普通 docker-compose up 会忽略 deploy 下的所有配置。
解决:将重启策略移到顶层 restart 属性:
YAML# 错误(非 Swarm 模式) services: app: image: my-app deploy: restart_policy: condition: on-failure # 正确(普通模式) services: app: image: my-app restart: on-failure
4. 容器重启循环导致 Docker 保护模式
现象:容器反复重启,系统日志显示 Docker 进入“重启循环”保护模式,停止自动重启。
根因:Docker 内置防重启循环机制——如果容器在短时间内频繁崩溃,Docker 会逐渐增加重启间隔,最终停止重启。
解决:
- 立即停止重启:
docker update --restart=no <container-name> - 检查容器日志,修复根本问题
- 使用
on-failure:3限制最大重启次数,避免无限循环
生产环境实践与注意事项
重启策略选择建议
| 服务类型 | 推荐策略 | 原因 |
|---|---|---|
| 无状态 Web 服务 | always | 即使正常退出也应重启,确保持续可用 |
| 有状态数据库 | unless-stopped | 手动停止后不重启,避免数据损坏 |
| 批处理任务 | on-failure:3 | 限制重启次数,避免无限重试 |
| 一次性初始化脚本 | "no" | 执行完成后不应重启 |
避免重启循环
- 为关键服务设置
healthcheck,确保容器在依赖就绪后才启动 - 使用
on-failure并指定max-retries,避免无限重启 - 在 Swarm 模式下设置
delay和window,错开重启时间
安全性建议
- 不要对数据库等有状态服务使用
restart: always:如果数据文件损坏,容器会不断重启,可能导致数据丢失。使用unless-stopped并配合外部备份机制。 - 避免资源竞争:多个容器同时重启可能导致 CPU/内存/端口冲突。在 Swarm 模式下使用
delay参数错开重启时间。 - 监控重启次数:使用
docker events或监控工具跟踪容器重启事件,及时发现异常。
常见问题 FAQ
Q: 为什么我设置了 restart: always,但手动 docker stop 容器后,它没有立即重启?
A: 这是 Docker 的设计行为。当用户手动停止容器时,Docker 会尊重用户意图,不会立即重启。但是,当 Docker 守护进程重启(例如主机重启)时,always 策略会生效并重启容器。如果你希望容器在手动停止后也不重启,应使用 unless-stopped 策略。
Q: on-failure 和 always 策略在容器退出码为 0 时有什么区别?
A: 当容器退出码为 0(正常退出)时,on-failure 策略不会重启容器,而 always 策略会重启容器。因此,对于需要持续运行的服务(如 Web 服务器),即使正常退出也应重启,应使用 always。对于一次性任务(如数据库迁移),正常退出后不应重启,应使用 on-failure 或 "no"。
Q: 如何在 Docker Compose 中设置重启的最大尝试次数?
A: 在普通模式下,可以使用 restart: on-failure:5 来设置最大重启次数为 5 次。在 Swarm 模式下,可以使用 deploy.restart_policy.max_attempts: 5 来设置。注意,on-failure 后的数字是可选参数,如果不指定,Docker 会无限尝试重启。
相关深度解决方案
在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 Docker Compose 环境变量配置实战:三种方式与避坑指南。
在配置当前服务时,如果您需要实现更复杂的架构或多源数据整合,建议配合参考我们整理的 多阶段构建 Docker 镜像体积过大?从 1.2GB 到 150MB 的实战优化。