Hotdry.

Article

Docker Compose 生产就绪检查清单:健康检查、依赖等待与资源隔离

聚焦 Docker Compose 自身配置细节,提供健康检查、依赖等待、网络重试与优雅关闭的生产就绪参数清单。

2026-05-06systems

很多团队在将 Docker Compose 从开发环境迁移到生产环境时,往往低估了配置文件中的细节差距。开发环境里手动重启容器不是什么大事,但生产环境中凌晨三点的宕机电话足以让人重新审视每一项配置。本文聚焦 Docker Compose 自身的工程化参数,提供一份可直接落地的生产就绪检查清单,涵盖健康检查、依赖等待策略、网络重试机制与优雅关闭四个关键维度。

健康检查:超越容器运行状态

docker ps 显示的 running 状态仅代表容器进程存在,并不意味着服务可以正常响应请求。健康检查是 Docker 提供的定期「体检」机制,通过执行指定命令来判断服务真实状态。返回码为 0 表示健康,非零表示不健康,连续多次失败后容器会被标记为 unhealthy。值得注意的是,健康检查失败本身不会触发容器重启,它的作用是暴露状态问题,实际的自愈能力需要结合重启策略实现。

健康检查有四个核心参数需要精细调优。interval 决定检查频率,生产环境通常设置为 30 秒左右,过于频繁会增加系统开销,过于稀疏则可能错过故障发现窗口。timeout 是单次检查的超时时间,建议设置为 5 到 10 秒,过短会导致误判,长时间则延迟故障发现。retries 定义连续失败多少次才将容器标记为不健康,这个参数与故障恢复时间直接相关。最后是 start_period,它为容器启动提供宽限期,在此期间的健康检查失败不会计入重试次数,对于需要较长初始化时间的应用(如数据库连接、缓存预热)至关重要,设置 30 到 60 秒可以有效避免服务尚未就绪就被标记为不健康的误判。

常见的健康检查命令需要根据服务类型选择。Web 服务使用 curl -f http://localhost:PORT/health 或自定义脚本;PostgreSQL 可用 pg_isready -U postgres;Redis 使用 redis-cli ping。这些命令的优势在于它们真正验证了服务的可用性,而不仅仅是端口监听。

依赖等待:从顺序启动到条件就绪

传统的 depends_on: [db, redis] 语法仅保证容器启动顺序,不保证服务真正可用。应用容器可能在数据库完成初始化之前就尝试建立连接,导致启动失败。Docker Compose V2 引入了基于健康检查的条件等待机制,通过 condition: service_healthy 参数实现真正的就绪等待。

配置时需要为被依赖的服务先定义健康检查,然后依赖方使用条件声明。以典型的 Web 应用为例,应用服务声明依赖数据库和缓存,并设置条件为 service_healthy,这样 Docker Compose 会等待这两个服务的健康检查通过后才启动应用容器。这种方式从根本上消除了「服务看起来启动了但实际不可用」的竞态条件。

对于多层级依赖链(服务 A 依赖服务 B,服务 B 依赖服务 C),需要为链路上的每个节点配置健康检查,并在依赖声明中逐层传递条件。需要特别注意的是避免循环依赖,且级联依赖会增加整体启动时间,设计时需要权衡解耦程度与启动性能。

网络重试与服务发现

生产环境中网络抖动是常态,容器首次启动时依赖的服务可能尚未就绪,除了依赖等待机制外,应用自身的重试策略同样关键。建议在应用代码中实现指数退避重试机制,初始重试间隔可设为 1 秒,最大重试间隔设为 30 秒,总重试时间覆盖健康检查的完整周期。对于使用连接池的数据库访问,首次获取连接失败后的重试逻辑需要格外注意,避免在未完全初始化的状态下反复重试浪费资源。

在 Docker Compose 网络层面,建议为生产环境显式定义自定义网络,而非使用默认网络,这样便于实施网络隔离和流量控制。每个服务明确声明所属网络,可以避免跨网络的不必要通信,同时为后续的流量监控和安全策略打下基础。

优雅关闭:信号处理与停止超时

容器收到 SIGTERM 信号后优雅停止是生产环境的基本要求。默认的 10 秒停止超时对于复杂应用往往不足够,数据库、消息队列等有状态服务需要更长时间完成数据刷盘和连接关闭。Docker Compose 通过 stop_grace_period 参数全局或为单个服务设置停止宽限期,建议设置为 30 秒到 60 秒,具体数值取决于服务的数据持久化需求。

应用容器内部需要正确处理 SIGTERM 信号。Node.js 进程收到终止信号后应停止接收新请求、完成当前请求处理、关闭数据库连接后再退出,而非直接退出。Go 语言的 signal.Notify 配合上下文取消是标准做法。忽略 SIGTERM 信号的容器会被 Docker 强制发送 SIGTERM 杀死,这可能导致数据丢失或不一致。

重启策略与自愈机制

重启策略决定了容器退出后的行为。生产环境推荐使用 restart: unless-stopped,它会在容器异常退出后自动重启,但手动执行 docker stop 后不会自动恢复,这与 restart: always 的区别在于:前者允许运维人员在维护期间主动停止服务而不必担心被自动拉起,后者则在 Docker 守护进程重启后会将所有容器重新启动,可能打乱维护节奏。

对于可能存在临时故障的服务(如外部 API 调用失败),可以使用 restart: on-failure:N 限制重启次数,避免进入无限重启循环。结合健康检查的 retries 参数,可以构建完整的故障检测与恢复链路:健康检查发现异常 → 重启策略触发容器重启 → 新容器重新初始化并通过健康检查恢复服务。

资源限制与隔离

单一容器耗尽系统资源导致整台服务器崩溃是生产环境的经典事故。Docker Compose 通过 deploy.resources 为每个容器设置资源天花板。limits 是硬限制,内存超限会触发 OOM Killer 杀死容器,CPU 超限会被节流但不会杀死。reservations 是软保证,告知调度器容器至少需要的资源量,生产环境建议为数据库和缓存预留足够资源以避免争抢。

生产环境的经验值可作为初始参考:Node.js 应用建议至少 512MB 内存,生产环境 1GB 以上;Python 应用 256MB 到 512MB;PostgreSQL 根据连接数和数据量设置 1GB 到 4GB;Redis 缓存 256MB 到 512MB。这些数值需要根据实际负载持续调优。

日志管理与磁盘防护

Docker 默认的 json-file 日志驱动会无限增长,不加限制的日志文件最终会撑爆磁盘。通过 logging 配置限制单个日志文件大小和文件数量,可以实现自动轮转。建议每个容器限制总日志大小在 30MB 左右(10MB 单文件 × 3 个文件),这已经足够排查问题,同时不会对磁盘造成压力。

生产就绪检查清单

将上述要点提炼为可逐项检查的清单。健康检查维度需要确认:每个有依赖的服务都配置了有效的健康检查命令;start_period 根据应用初始化时间合理设置;intervaltimeoutretries 参数经过调优而非使用默认值。依赖等待维度需要确认:所有依赖关系使用 condition: service_healthy 而非简单的数组声明;依赖链路完整无断裂。优雅关闭维度需要确认:所有服务正确处理 SIGTERM 信号;stop_grace_period 足够完成数据持久化;无状态服务不阻塞退出。资源隔离维度需要确认:所有服务配置了内存和 CPU 限制;limits 和 reservations 数值经过实际负载验证;日志轮转配置已启用。监控告警维度需要确认:健康检查状态已接入监控系统;容器重启事件有告警;资源使用率有阈值告警。

这些检查项不需要一次性全部完成,但每补充一项,生产环境的稳定性就提升一个台阶。Docker Compose 从开发玩具变成生产可靠方案,差异往往就在这些具体参数的配置细节里。

资料来源:https://eastondev.com/blog/en/posts/dev/20260424-docker-compose-production/

systems