本节摘要:编队的协调学——服务名即域名的机制落地、"起来了"与"就绪了"的差别(depends_on 加健康检查)、环境变量与配置文件的多环境管理。本节收官主线任务:把整支船队写成一个可交付的文件。
前三节解决了"怎么写、怎么跑",本节解决"怎么配合"。多容器应用的事故大头不在单箱配置,而在箱与箱的协调上:应用起来时数据库还没就绪、两套环境用同一份配置把测试数据写进生产库、密钥硬编码进了声明文件进了代码库——本节三个主题对应这三类事故。
6.2 的文件里应用靠 DB_HOST=db 找到数据库,这个 db 不是 IP 不是别名,是服务名。机制链条完整过一遍:编队自动建一条航道,所有服务接入;引擎在这条航道上跑着内建域名解析;每个服务起吊时以服务名注册;任何箱子按服务名发起连接,解析自动完成。验证一下这条链路:
# 在编队里验证服务名解析与连通 docker compose exec web sh -c "nc -zv db 5432" # db (172.20.0.2:5432) open # 同一条航道上的端口对内全部直通:无需泊位映射 # (ports 字段是发给宿主机外部用的,编队内部互访不需要它)
工程含义再次强调:编队内部通信不需要 ports。数据库服务在声明里连 ports 字段都可以不写——外部世界碰不到它,只有同航道的邻居能访问,安全白赚。给需要对外服务的应用配 ports,内部服务一律裸奔在航道里。
多容器应用的第一翻车点:应用起得比数据库快,连库失败,崩溃退出,重启策略再拉起,再失败……循环报错。新手方案是"睡三秒再连"——不可靠且难维护,数据库慢一点照样崩。正确方案是声明依赖加健康检查:
# 依赖与就绪的标准写法 services: web: depends_on: db: condition: service_healthy # 不是"db 起了",而是"db 健康了" # ... db: image: postgres:16-alpine healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s # 每五秒探一次 timeout: 3s # 单次探测超时 retries: 5 # 连续失败五次才判不健康
condition: service_healthy 的语义精确:依赖方等的是"健康",不是"存在"。健康定义由 healthcheck 给出——数据库镜像大多自带就绪探测命令,拿来即用。对照实验感受差别:
# 起航看输出:数据库先起、等健康、应用后起 docker compose up -d # [+] Running 3/3 # Container web-fleet-db-1 Healthy <- 健康检查通过 # Container web-fleet-web-1 Started <- 应用此时才起 # 查看健康状态(编队名册的健康标注来自 healthcheck) docker compose ps # SERVICE STATUS # db Up 2 minutes (healthy) # web Up 1 minute
应用自身也应配 healthcheck——它让依赖你的服务(以及未来的调度平台)也能正确等待你。就绪探测通常探一个轻量的健康端点(返回 200 即算活着),这是 12-factor 风格应用的标配。
配置管理的三段式方案,按敏感度与复用度递进。
第一段:声明内联。 环境变量直接写在声明里,适合无敏感内容的默认值。第二段:环境文件。 把变量抽到随文件同目录的环境文件,声明里只留引用:
# compose.yaml 里只留引用 services: db: image: postgres:16-alpine env_file: - db.env # 变量本体在环境文件里
# db.env(与声明文件同目录,加入版本库忽略清单) POSTGRES_PASSWORD=dev-only-pass POSTGRES_DB=orders
第三段:覆盖文件。 多环境复用同一份主文件,差异项放进覆盖文件,起航时叠加:
# 主文件 + 覆盖文件:测试环境的差异配置 docker compose -f compose.yaml -f compose.test.yaml up -d # 覆盖文件里的同名字段会覆盖主文件(如不同的密码、不同的端口)
环境变量还有一个容易踩的优先级细节:shell 里已经导出的同名变量(compose 运行环境读到的),会覆盖声明里不带默认值的引用写法。排障时若发现"文件里写的值没生效",先 echo 确认 shell 侧有没有同名变量,再查环境文件——优先级从高到低通常是:shell 环境、声明内联、环境文件。理不清时别猜,直接渲染最终配置:
# 渲染最终配置:变量替换与覆盖叠加后的成品,所见即所得 docker compose config # 输出即最终生效的完整声明,每个服务的环境变量一目了然
把这条命令与 6.2 的字段说明对照着用,声明文件的每一层叠加就都成了可当场验证的事实,而不是靠记忆推断。
这套组合的价值在环境语义的严格分离:开发用内联默认值、密钥进环境文件并拒入版本库、测试与生产的差异用覆盖文件显式管理。密钥管理的基本红线:任何密码都不该出现在被提交的声明文件里——环境文件加版本库忽略是底线,更严格的企业做法走密钥管理服务(第 7 章安全基线再深化)。
把全章知识拧回主线任务:Web 加数据库加缓存的船队,现在是一份文件加两条命令的交付物——写清服务与依赖(6.2)、就绪与健康(本节)、配置与环境分离(本节),起航 up、收港 down(6.3)。换台机器?拷走声明与装箱单,up -d,收工。这就是多容器应用的工程化交付,也是你入职容器时代以来第一个真正意义上的系统级成果。
编队毕业。下一章驶向航线深处:安全、流水线、部署、排错,与自动化港区之门。