2. Docker Compose 入门:Compose 文件结构、服务定义、网络与卷配置、多容器编排示例
2.1 为什么需要 Docker Compose
在生产级 DAG 调度系统中,一个完整的任务往往依赖多个容器协同工作:调度器、执行器、数据库、消息队列、日志收集器。如果逐个使用 docker run 启动,不仅命令冗长,而且难以管理容器间的网络依赖、数据持久化和启动顺序。Docker Compose 通过一个声明式 YAML 文件,将多容器编排的复杂度封装为可重复、可版本化的配置。
核心价值:Compose 将“基础设施即代码”理念落地到单机多容器场景,是后续 DAG 调度边界发布与回滚的配置基础。
2.2 Compose 文件结构(YAML 骨架)
Compose 文件默认名为 docker-compose.yml,采用 YAML 格式。其顶层结构包含三个核心字段:services、networks、volumes。下面是一个标准骨架:
version: '3.8'
services:
# 服务定义区
networks:
# 网络定义区
volumes:
# 卷定义区
| 顶层字段 | 作用 | 是否必填 |
|---|---|---|
version |
指定 Compose 文件格式版本,推荐 3.8 或以上 |
是 |
services |
定义所有容器服务,每个服务对应一个镜像和运行参数 | 是 |
networks |
声明自定义网络,用于服务间隔离与通信 | 按需 |
volumes |
声明命名卷,用于数据持久化与共享 | 按需 |
2.3 服务定义详解
每个服务至少需要指定 image 或 build。常用配置项如下:
- image:指定镜像名称及标签,如
postgres:15。 - build:指定 Dockerfile 路径,用于本地构建镜像。
- ports:端口映射,格式
"宿主机端口:容器端口"。 - environment:环境变量,支持列表或字典格式。
- depends_on:声明服务依赖,控制启动顺序。
- volumes:挂载卷,支持命名卷和绑定挂载。
- networks:指定服务加入的网络。
- restart:重启策略,如
always、on-failure。
示例:一个简单的 Web 服务定义
services:
web:
image: nginx:alpine
ports:
- "8080:80"
networks:
- frontend
restart: always
2.4 网络配置:服务间通信的桥梁
Compose 默认会创建一个名为 <项目名>_default 的桥接网络,所有服务自动加入。但在复杂场景中,建议显式定义网络以实现分层隔离:
- frontend:对外暴露的服务(如 Nginx、API 网关)放入此网络。
- backend:内部业务服务(如应用服务器)放入此网络。
- database:数据库、缓存等数据层服务放入此网络。
networks:
frontend:
driver: bridge
backend:
driver: bridge
database:
driver: bridge
服务通过 networks 字段加入对应网络后,可直接使用服务名作为主机名进行通信,无需关心 IP 地址。
2.5 卷配置:数据持久化与共享
容器默认是非持久化的,重启后数据丢失。Compose 通过 volumes 解决此问题,支持两种方式:
| 类型 | 定义位置 | 生命周期 | 适用场景 |
|---|---|---|---|
| 命名卷 | 顶层 volumes 声明,服务内引用 |
独立于容器,docker compose down 默认不删除 |
数据库数据、配置文件持久化 |
| 绑定挂载 | 直接在服务 volumes 中写宿主机路径 |
依赖宿主机目录,手动管理 | 开发热重载、日志输出 |
volumes:
pgdata: # 命名卷声明
driver: local
services:
db:
image: postgres:15
volumes:
- pgdata:/var/lib/postgresql/data # 使用命名卷
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # 绑定挂载
注意:绑定挂载使用绝对路径或相对路径(相对于 Compose 文件所在目录)。命名卷在
docker compose down -v 时会被删除,生产环境需谨慎操作。
2.6 多容器编排示例:DAG 调度基础栈
下面是一个完整的 docker-compose.yml,模拟 DAG 调度系统的最小依赖集合:调度器(模拟)、执行器(模拟)、PostgreSQL 数据库、Redis 缓存。
version: '3.8'
services:
scheduler:
image: alpine:latest
command: ["sh", "-c", "while true; do echo 'Scheduling DAG...'; sleep 10; done"]
depends_on:
- db
- redis
networks:
- backend
- database
restart: always
executor:
image: alpine:latest
command: ["sh", "-c", "while true; do echo 'Executing task...'; sleep 15; done"]
depends_on:
- scheduler
networks:
- backend
- database
restart: always
db:
image: postgres:15
environment:
POSTGRES_USER: daguser
POSTGRES_PASSWORD: dagpass
POSTGRES_DB: dagdb
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- database
restart: always
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
networks:
- database
restart: always
networks:
backend:
driver: bridge
database:
driver: bridge
volumes:
pgdata:
driver: local
redisdata:
driver: local
2.7 常用 Compose 命令速查
| 命令 | 作用 | 常用选项 |
|---|---|---|
docker compose up -d |
后台启动所有服务 | --build 强制重新构建镜像 |
docker compose down |
停止并移除容器、网络 | -v 同时删除命名卷 |
docker compose ps |
查看服务运行状态 | — |
docker compose logs -f |
实时查看所有服务日志 | 可指定服务名,如 logs -f scheduler |
docker compose exec |
在运行中的容器内执行命令 | 如 exec db psql -U daguser |
最佳实践:将
docker-compose.yml 纳入 Git 版本管理,配合 .env 文件管理环境差异(开发/测试/生产)。这是后续实现“边界发布”与“回滚”的配置基线。