07入门:Compose进阶

1167 字
6 分钟
07入门:Compose进阶

第 7 关 Compose 进阶#

本关的产出:把第 6 关那份文件补上「顺序」和「就绪」两层,再用多文件与 profiles 管住本地、生产两套环境。

7.1 起得来,不等于能连#

第 6 关那份文件,up -d 之后有个问题:web 里的程序连 db 会失败一阵。第 2 关那条坑——mysql 第一次启动要先初始化数据目录,得等十几秒——到了 compose 里原样复现。

compose 起容器有顺序,但顺序来自 depends_on,得自己写:

services:
web:
image: nginx
depends_on:
- db

写了它,db 会先于 web 创建;down 的时候反过来,web 先拆。(不写 depends_on 也起得来,只是顺序不保证。)

但要注意它管的是什么:depends_on 只等 db 跑起来,不等 db 能应答。mysql 的容器起来了、进程在跑,那十几秒的初始化里 3306 上仍然没人应答——web 该连还是连不上。

所以「起来了」和「就绪了」是两回事。 要表达后者,得先定义什么叫就绪。

7.2 定义一个「就绪」的判据#

在 db 上加一段 healthcheck:

db:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=hecloud
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-phecloud"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s

逐项:

  1. test:判据本身。它是一条命令,退出码为 0 就算这一轮健康。这里用 mysqladmin ping——数据库能应答,它才返回 0。
  2. interval:隔多久查一轮。
  3. timeout:单轮超时就当这轮失败。
  4. retries:连续失败几次,才把状态判成「不健康」。
  5. start_period:开头的宽限期。这期间内的失败不计数——mysql 初始化慢,就是靠它不至于一上来被误判成挂了。

看状态:

docker compose ps

STATUS 那一列会从 (health: starting) 变成 (healthy)。健康检查是容器身上的一层属性,docker inspect 里也看得到。

7.3 等到就绪再起下一个#

有了判据,depends_on 就能等它:

web:
image: nginx
depends_on:
db:
condition: service_healthy

condition 有三种:

  1. service_started:只等跑起来——就是 7.1 那个默认行为。
  2. service_healthy:等健康检查判成 healthy 才算过了。
  3. service_completed_successfully:等它跑完退出,且退出码为 0。给那种「一次性做完就走」的初始化服务用。

改成 service_healthy,web 会一直等到 db 报 healthy 才被创建——第 2 关那个坑,到这儿才算收口。

易踩的坑:condition 写在依赖方(web)上,healthcheck 得写在被依赖方(db)上——两处别写反。对面没有 healthcheck 时,service_healthy 就没有依据可等。

7.4 一套文件,拆成多份#

本地开发和生产跑的不一样:本地要挂源码、开调试端口,生产不要。把这些都塞进一个文件,靠 if 之类的思路去开关,很快就乱了。compose 的办法是按层叠文件。

两个文件,后一个叠在前一个上面:

docker compose -f compose.yaml -f compose.prod.yaml up -d

按命令行顺序合并,后面的覆盖前面的。 怎么覆盖,看是哪一类条目,记不住就先跑 docker compose config 看合并后的结果:

  1. 单值项(image、command):后面的直接盖掉前面的。
  2. 键值项(environment、labels):按键名合并,同名的以后一个为准,新键加上去。
  3. 挂载(volumes):按容器里的路径合并,同一个路径以后一个为准。
  4. 端口列表(ports、expose):累加——两边都留,加了新的旧的也不消失。

易踩的坑:文件名是 compose.override.yaml 时会被自动叠上,不用写 -f——这是给本地开发留的口子。哪天发现「为什么本地多了一份配置」,通常就是它。

7.5 按需起:profiles#

生产不要的东西,除了用 7.4 的文件覆盖关掉,还可以一开始就不让它起。给服务挂一个 profile 名:

services:
db:
image: mysql
phpmyadmin:
image: phpmyadmin
profiles:
- debug

规矩很简单:

  1. 没写 profiles 的服务永远起——db 就是。
  2. 写了 profiles 的只在它那个 profile 激活时才起——phpmyadmin 平时不出现。

激活:

docker compose --profile debug up -d

要开多个就写多遍 --profile,或者逗号隔开;--profile "*" 全开。也可以直接点名:

docker compose up -d phpmyadmin

被点名的服务就算 profile 没激活也会起——临时跑个调试工具时会用到。

易踩的坑:docker compose down 只停没 profile 的服务,phpmyadmin 这种得用 docker compose down phpmyadmin 或带 --profile 才停得掉。

这一关的产出:服务之间能表达「等它真的就绪」,以及一套文件管住多套环境的两种手法。下一关回到单个容器,钻进一个第 2 关就绕开的问题——容器里那个进程,是怎么被启动、被停掉的。

本关命令速查#

Compose 的命令与用法,见 命令速查表 · Compose。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
07入门:Compose进阶
https://hecloud.top/posts/tech/docker/07compose进阶/
作者
贺小云
发布于
2026-09-23
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
贺小云
热爱技术与折腾的博客 Dancing with uncertainty. 与不确定性共舞
公告
出于成本考虑,贺云已全面转型Serverless架构
分类
标签
碎碎念
站点统计
文章
91
分类
5
标签
44
总字数
103,192
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0