跳到内容

第 0 卷 / 第 7 章 / 第 3 课

7.3 用 Compose 管理多服务项目 ​

前置知识:写一个 Dockerfile

预计时间:20 分钟

练习环境:Docker Engine 与 docker compose

完成标志:能验证 Compose 模型,并解释项目命名、服务发现、就绪条件和命名卷生命周期

单个容器已经能启动。真实项目还可能有数据库、缓存和后台任务。你不想每次手工重敲名称、网络、卷和启动顺序。

Compose 用一份 YAML 描述一个应用项目。项目名会为容器、网络和卷建立命名边界,服务名则成为默认网络中的 DNS 名称。

一个安全、可清理的练习 ​

先创建隔离目录,再把配置保存为首选文件名 compose.yaml:

bash
compose_workdir=$(mktemp -d)
compose_project="workshop-ch07-${RANDOM}-${RANDOM}"
cd "$compose_workdir"
yaml
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"。

先解析最终模型,再创建资源:

bash
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 删除本项目容器和默认网络,但默认保留命名卷。验证卷仍在,再明确删除:

bash
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 volumeDocker 管理、独立于容器生命周期的存储
Bind mount把明确的主机路径挂进容器,直接受主机路径与权限影响

服务之间使用容器端口,例如应用连 db:5432。只有主机也需要访问时才写 ports;数据库只供同一 Compose 项目使用时通常不必发布到主机。

yaml
ports:
  - "127.0.0.1:18080:8080"

这是服务下的配置片段,需要放在实际服务定义中;在 Docker Engine 28+ 的默认 bridge/NAT 网络下,把主机发布地址限制为回环地址。端口占用时换一个未使用的主机端口,不要先杀掉不认识的进程。

depends_on 不等于应用就绪 ​

短语法 depends_on: [db] 只保证依赖先启动到 running 状态。数据库进程可能仍在恢复。需要就绪门槛时给依赖配置 healthcheck,并使用:

yaml
depends_on:
  db:
    condition: service_healthy

即便如此,应用仍应为短暂网络故障实现有上限的重试、超时和错误日志。健康检查不是永久可用保证。

密码与配置 ​

不要把真实密码直接提交进 compose.yaml。本地开发可使用未提交的环境文件或 Compose secret,生产环境应接入部署平台的秘密管理。注意 docker compose -p "$compose_project" config 可能展开环境变量,分享输出前仍需脱敏。

yaml
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 官方文档。

→ 下一步:Docker 综合实验

Built with VitePress | Software Systems Atlas