7.3 用 Compose 管理多服务项目
前置知识:写一个 Dockerfile
预计时间:20 分钟
练习环境:Docker Engine 与
docker compose完成标志:能验证 Compose 模型,并解释项目命名、服务发现、就绪条件和命名卷生命周期
单个容器已经能启动。真实项目还可能有数据库、缓存和后台任务。你不想每次手工重敲名称、网络、卷和启动顺序。
Compose 用一份 YAML 描述一个应用项目。项目名会为容器、网络和卷建立命名边界,服务名则成为默认网络中的 DNS 名称。
一个安全、可清理的练习
先创建隔离目录,再把配置保存为首选文件名 compose.yaml:
compose_workdir=$(mktemp -d)
compose_project="workshop-ch07-${RANDOM}-${RANDOM}"
cd "$compose_workdir"name: workshop-ch07
services:
writer:
image: busybox:latest
command: ["sh", "-c", "printf 'volume survives container removal\\n' > /data/message.txt"]
volumes:
- workshop-data:/data
reader:
image: busybox:latest
command: ["cat", "/data/message.txt"]
depends_on:
writer:
condition: service_completed_successfully
volumes:
- workshop-data:/data:ro
volumes:
workshop-data:本页始终用 -p "$compose_project" 覆盖配置中的固定 name,为这次练习建立单独的资源范围。清理时继续使用同一个项目名,不能只靠 workshop-ch07 前缀认定所有权。
顶层 version 已是向后兼容字段,当前 Compose 会忽略它并使用最新规范,因此新文件不必写 version: "3.8"。
先解析最终模型,再创建资源:
docker compose -p "$compose_project" config
docker compose -p "$compose_project" run --rm reader
docker compose -p "$compose_project" ps --all
docker compose -p "$compose_project" down你应看到 volume survives container removal。down 删除本项目容器和默认网络,但默认保留命名卷。验证卷仍在,再明确删除:
docker volume ls --filter "label=com.docker.compose.project=$compose_project"
docker compose -p "$compose_project" down --volumes
cd
ls -ld -- "$compose_workdir"
rm -r -- "$compose_workdir"不要把 down --volumes 用在需要保留数据的数据库项目上。Docker 官方也明确说明,普通 down 默认保留命名卷;删除前必须先判断数据是否仍需要。
Compose 管理的对象
| 对象 | 说明 |
|---|---|
| Project | 一次应用部署及其资源边界;可用顶层 name 或 -p 指定 |
| Service | 一类容器的配置,不等于某个固定容器实例 |
| Network | 服务间通信边界;同一默认网络可用服务名解析 |
| Named volume | Docker 管理、独立于容器生命周期的存储 |
| Bind mount | 把明确的主机路径挂进容器,直接受主机路径与权限影响 |
服务之间使用容器端口,例如应用连 db:5432。只有主机也需要访问时才写 ports;数据库只供同一 Compose 项目使用时通常不必发布到主机。
ports:
- "127.0.0.1:18080:8080"这是服务下的配置片段,需要放在实际服务定义中;在 Docker Engine 28+ 的默认 bridge/NAT 网络下,把主机发布地址限制为回环地址。端口占用时换一个未使用的主机端口,不要先杀掉不认识的进程。
depends_on 不等于应用就绪
短语法 depends_on: [db] 只保证依赖先启动到 running 状态。数据库进程可能仍在恢复。需要就绪门槛时给依赖配置 healthcheck,并使用:
depends_on:
db:
condition: service_healthy即便如此,应用仍应为短暂网络故障实现有上限的重试、超时和错误日志。健康检查不是永久可用保证。
密码与配置
不要把真实密码直接提交进 compose.yaml。本地开发可使用未提交的环境文件或 Compose secret,生产环境应接入部署平台的秘密管理。注意 docker compose -p "$compose_project" config 可能展开环境变量,分享输出前仍需脱敏。
secrets:
db_password:
file: ./secrets/db_password.txt这段只定义顶层 secret 来源;还需在对应服务下增加 secrets: [db_password],才能在容器的 /run/secrets/db_password 读取它。秘密文件本身必须排除出版本控制并限制权限。
Volume 与 bind mount
- 数据库数据适合命名卷:由 Docker 管理,容器删除后仍可保留。
- 本地源码热更新常用 bind mount:主机改动直接映射进容器。
- bind mount 默认可能允许容器修改主机文件;能只读就加
:ro。 - 卷不是备份。仍需验证备份、恢复、迁移和保留策略。
模型已经清楚。最后用限定名称和回环端口完成一轮可逆实验。启动与就绪条件可继续核对 Compose 官方文档。