在生产环境中使用 Docker Compose 时,许多团队仅完成端口映射和卷挂载就将容器投入运行,忽略了健康检查、重启策略和服务依赖顺序等关键配置。这种做法导致的典型问题包括:容器显示「运行中」但实际已「死亡」,日志文件无限增长直至磁盘耗尽,以及崩溃服务无限重启导致 CPU 和内存耗尽。根据行业调研数据,容器「僵尸状态」平均每次故障需要耗费运维人员 3.2 小时进行排查。本文将聚焦于 plain Docker Compose 在 2026 年的具体配置细节,提供可直接落地的参数方案和监控要点。
健康检查的核心价值与配置逻辑
Docker 容器的「运行中」状态仅表示进程存在,并不能反映应用程序的真实健康状况。数据库连接失败、端口未监听、进程冻结等情况发生时,Docker 本身无法感知。健康检查(healthcheck)充当了容器的「心跳监护仪」,通过定期执行检查命令来判断应用是否能正常响应。配置健康检查时,五个核心参数需要协同调优:test 定义检查命令,interval 指定检查间隔,timeout 设定单次检查的超时时间,retries 决定连续失败多少次后标记为不健康,而 start_period 则为容器提供启动预热时间。
一个典型的生产级健康检查配置如下所示:间隔设为 10 秒,超时时间 5 秒,重试次数 5 次,启动预热期 30 秒。这里存在一个容易被忽视的约束条件:timeout 必须小于等于 interval,否则上一次检查尚未完成,下一次检查就已开始,导致检查线程堆积。start_period 参数同样不可或缺,对于数据库等启动较慢的服务,如果预热时间过短,健康检查会误判容器已「死亡」,在容器尚未完全初始化时就将其标记为不健康状态。
针对不同类型的服务,需要采用差异化的检查命令。PostgreSQL 可使用内置的 pg_isready 工具,命令简洁且专为判断数据库是否就绪而设计。MySQL 和 MariaDB 依赖 mysqladmin ping,需要注意密码中的美元符号需要双写为 $$ 以转义 YAML 解析。Redis 的 ping 命令返回 PONG 响应,通过管道传递给 grep 过滤可确保检查结果的准确性。对于 HTTP 服务,建议使用 curl 的 -f 参数,该参数在收到非 2xx 状态码时会返回非零退出码,从而正确触发健康检查失败。使用 Alpine 等精简镜像时需注意,curl 可能未预装,此时可改用 wget 或在 Dockerfile 中提前安装检查工具。
服务依赖顺序的精确控制
容器启动顺序错误是生产环境的常见痛点:数据库尚未就绪,但 API 容器已启动,导致连接失败、错误频发、服务崩溃。Docker Compose 的 depends_on 指令解决了这一问题,但在生产环境中,简单罗列依赖关系远远不够,必须配合 condition: service_healthy 条件才能实现真正的「健康等待」机制。
当在 depends_on 中指定 condition: service_healthy 时,Docker Compose 会阻塞依赖服务的启动,直到被依赖容器的健康检查返回 healthy 状态。这意味着 API 容器不会盲目启动,而是等待 PostgreSQL 和 Redis 都通过健康检查后再启动,从根本上避免了「数据库未就绪、API 强行连接」的场景。需要特别强调的是,condition: service_healthy 要求被依赖的服务必须配置了有效的 healthcheck,否则 Compose 会无限等待或提前启动。
对于需要严格启动顺序的多服务架构,推荐的配置模式如下:先为核心数据存储服务(PostgreSQL、Redis、MongoDB)配置健康检查和重启策略,再为应用服务配置 depends_on 并指定 service_healthy 条件,最后为前端或入口服务配置对后端服务的健康等待。这种层级化的依赖配置确保了数据层完全就绪后,应用层才开始接收流量。
重启策略的工程化选择
容器崩溃后是否自动重启看似简单,但策略选择不当会造成严重后果。restart: always 会无条件重启任何退出场景,包括代码 bug、配置错误、数据库连接失败等根本问题未解决的情况。后果是容器进入「崩溃循环」,日志快速堆积,CPU 被反复消耗,运维人员甚至无法察觉服务已彻底死亡。
生产环境推荐使用 on-failure 配合 max_attempts 参数的组合策略。on-failure 仅在容器异常退出(非零退出码)时触发重启,而 max_attempts 限制了最大重启次数(通常设为 3 次),超过限制后容器保持停止状态,为运维人员介入调查问题提供了窗口。这个组合既赋予了故障自动恢复能力,又避免了无限重启的风险。
重启策略还有两个关键参数需要调优:delay 定义重启间隔时间,过短可能导致前一次容器的资源尚未完全释放,过长则延长恢复时间,一般建议 5 至 10 秒。window 参数常被忽视,它定义了「重启成功后多长时间内未再次崩溃才算真正恢复」,例如设置 window: 120s 意味着如果容器在重启后 120 秒内再次崩溃,当前的重试次数仍被计入,这避免了「成功启动一秒后立即崩溃」被误判为恢复的情况。
健康检查与重启策略的协同机制
健康检查和重启策略并非独立运作,而是形成一条故障处理链条:当健康检查连续失败达到 retries 次数后,容器被标记为 unhealthy;如果此时配置了 restart_policy,Docker 会尝试重启容器;重启后健康检查计数器重置,若检查通过则恢复正常,若仍然失败则继续重启尝试直到 max_attempts 耗尽。这个链条赋予了小故障自动恢复的能力,同时通过重试次数限制控制了无限重启的风险。
一个常见的误解是「健康检查失败会触发重启」,实际上健康检查失败仅标记容器为 unhealthy,是否重启取决于 restart_policy 的 condition 配置。在某些场景下,运维人员可能希望健康检查失败时仅发出告警而不重启,此时可将 condition 设为 on-failure 并依赖外部监控系统(如 Prometheus health_exporter)来触发告警和人工介入。
日志管理与磁盘防护
日志文件无限增长是生产环境的隐蔽杀手。Docker 默认使用 json-file 日志驱动,不会自动清理旧日志,容器持续运行数周后,单个日志文件可能达到数十 GB。一次凌晨的磁盘告警通常源于日志已将磁盘空间耗尽,这在实际运维中并不罕见。
生产环境必须配置日志轮转。通过在 logging 配置中指定 max-size、max-file 和 compress 参数,可以严格控制单个容器可占用的日志空间。例如设置 max-size: "10m" 和 max-file: "3" 后,单个容器最多保留 3 个各 10MB 的日志文件,总计 30MB,超出时最旧的文件会被删除或压缩。对于日志量较大的 API 服务,可适当放宽至 50m × 5;对于数据库和缓存服务,10m × 3 通常足够。
Docker 还支持 local 日志驱动,相比 json-file 效率更高且内置轮转功能,但代价是无法直接通过 docker logs 查看日志内容,需要额外配置。对于多服务器大规模部署的场景,建议考虑 Fluentd、ELK Stack 或 Loki + Grafana 等集中式日志方案,将日志统一收集和分析。
完整配置模板与关键要点
综合以上各项配置,一个生产级的 docker-compose.yml 应包含以下核心要素:为每个有状态或外部依赖的服务配置 healthcheck;使用 depends_on 配合 condition: service_healthy 控制启动顺序;为所有长期运行的服务配置 on-failure 重启策略并设置 max_attempts;为所有容器配置日志轮转参数。以下模板展示了 PostgreSQL + Redis + API 的标准生产配置模式:
数据库服务配置中,healthcheck 使用 pg_isready 检测数据库就绪状态,start_period 给予 30 秒初始化时间,重启策略使用 on-failure 配合 3 次重试限制,日志限制在 30MB 总量。Redis 服务配置类似,healthcheck 通过 redis-cli ping 验证,start_period 仅需 5 秒(Redis 启动较快)。API 服务配置 depends_on 等待 postgres 和 redis 都通过健康检查后启动,healthcheck 通过 curl 检测应用自身的健康端点,重启延迟设为 10 秒以给健康检查更多缓冲时间。
配置中还有两个值得关注的细节:不同服务的日志大小应差异化设置,数据库和缓存日志量较小,应用服务日志量可能较大;重启延迟也应根据服务启动速度调整,启动慢的服务(如数据库)延迟可稍短,因为需要更多时间恢复状态,启动快的服务延迟可稍长,为健康检查提供更充裕的判断时间。
常见问题排查路径
健康检查持续失败但应用实际运行正常是高频问题,首要排查方向是检查检查命令所需工具是否存在于容器内,精简镜像常缺少 curl、pg_isready 等工具,可通过 docker exec 手动验证命令可执行性,其次检查健康检查端点本身是否正常返回预期响应,最后使用 docker inspect 查看健康检查历史记录以定位具体失败原因。
容器反复重启且日志充满重启记录时,应首先检查容器退出码判断失败类型:退出码 1 表示一般错误,137 表示被 OOM Kill,139 表示段错误,其次查看重启次数验证 max_attempts 是否生效,最后检查容器日志定位具体错误信息。磁盘空间告警时,使用 du 命令快速定位最大的日志文件,检查日志轮转配置是否生效,紧急情况下可先用 truncate 命令临时清理日志文件。
资料来源
本文配置参数和最佳实践参考自 EastonDev 技术博客的 Docker Compose 生产部署指南,该文详细阐述了 healthcheck 配置语法、常见服务的检查命令、restart_policy 各参数的作用机制以及日志管理的完整方案。