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 地址。

Compose 网络分层架构 Frontend 网络(对外暴露) Nginx / API Gateway Backend 网络(业务逻辑) App Server / Worker / Scheduler Database 网络(数据层) PostgreSQL / Redis / RabbitMQ 服务名即主机名,跨网络通信需显式加入对应网络 例如:web 可通过 backend 网络访问 app

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
DAG 调度基础栈:服务依赖与网络关系 Scheduler 调度器(模拟) Executor 执行器(模拟) PostgreSQL 数据库 Redis 缓存 database 网络 backend 网络 depends_on 控制启动顺序,但不保证服务就绪 生产环境需配合 healthcheck 或等待脚本

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 文件管理环境差异(开发/测试/生产)。这是后续实现“边界发布”与“回滚”的配置基线。