3. Compose文件结构详细回顾归纳总结

聊到 Compose 文件结构,很多人第一反应就是「不就是个 YAML 嘛」。说得没错,但真正在 CI 里用它做快照回归测试时,细节上的坑往往让人头疼。我个人习惯把 Compose 文件拆成三个层面来看:元信息层、服务定义层、基础设施层。下面我结合项目经验,带你系统地捋一遍。

Compose 文件结构总览 version / name 文件格式版本 services 服务定义(核心) 基础设施 networks/volumes/configs 版本兼容性 镜像与构建 端口与变量 依赖与健康 持久化与网络隔离 ⚠️ 核心要点 services 是唯一必填的顶层字段

3.1 顶层字段:不止是 version 和 services

很多同学以为 Compose 文件只有 version 和 services,其实还有 networks、volumes、configs、secrets 等。在 CI 快照回归里,基础设施的定义一旦写错,整个环境就崩了。我遇到过三回,都是因为没显式声明网络,导致容器间互相找不到。下面这张表帮你快速定位每个字段的用途:

字段是否必填典型用途CI 快照中易踩的坑
version是(推荐)指定 Compose 文件格式版本新版引擎已弃用 version,可能导致校验失败
name否项目名称,影响容器命名前缀不指定时默认使用目录名,CI 中可能冲突
services是定义容器化应用服务依赖顺序错乱导致启动失败
networks否容器间网络隔离/互联忘记创建则容器自动加入默认网络,快照不一致
volumes否持久化数据或共享目录挂载路径写路径,CI 环境不同会报错
configs / secrets否注入配置或敏感数据文件权限或路径写死,导致加载失败

3.2 services:服务定义的灵魂

services 里的每个键对应一个容器。你想想看,在 CI 回归测试中,我们要精确控制每个容器的镜像版本、环境变量、端口映射、健康检查等。下面是我常用的几个核心配置项:

  • image / build:指定镜像来源。我一般用 image: myapp:${CI_COMMIT_SHA} 来保证快照的确定性。
  • environment:环境变量。千万注意不要在 YAML 里写 DB_PASSWORD=123456 这种硬编码,用 ${DB_PASSWORD} 配合 .env 文件。
  • ports:端口映射。快照回归里尽量用 0 随机端口,避免冲突。
  • depends_on:启动依赖。但依赖只控制顺序,不管健康状态,要配合 condition: service_healthy。
  • healthcheck:健康检查。我在一个项目里因为没配健康检查,依赖服务当成了「已启动」,结果测试全跑挂。
💡 我的一点小建议:在 CI 里做快照之前,先把 services 里的 depends_on 和 healthcheck 全部显式写出来,不要图省事用默认值。这样生成的快照才是可复现的。

3.3 networks 与 volumes:常见的「隐形杀手」

这两个字段平时容易被忽略,但恰恰是导致回归错误的重灾区。我曾经在 Jenkins 里跑 CI,本地测试好好的,上流水线就报 network not found。查了半天,原来是 Compose 文件没写 networks: 声明,结果不同构建任务共用默认网络冲突了。

来看一个标准写法:

version: '3.8'
services:
  app:
    image: myapp:latest
    networks:
      - frontend
      - backend
  db:
    image: postgres:13
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes 这边更要注意。用 volume: 而不是 bind mount 能保证在不同 OS 下路径一致性。比如:

volumes:
  data:
    driver: local

services:
  db:
    volumes:
      - data:/var/lib/postgresql/data
⚠️ 避坑指南:我曾经在 Windows 上用 WSL 写 Compose 文件,volumes 里写了个 ./data:/data,结果 Linux CI 环境里路径解析出问题,数据全丢了。后来统一用命名卷,再也没出过这种问题。

3.4 实际案例:一个完整的 CI 快照回归 Compose 文件

下面这个例子是我去年在微服务项目中用的,包含了上述所有核心要素。你可以直接抄走作为模板:

version: '3.8'
name: snapshot-regression-test

services:
  auth-service:
    build:
      context: ./auth
      dockerfile: Dockerfile.ci
    image: auth:${COMMIT_SHA:-latest}
    environment:
      - DB_HOST=postgres
      - REDIS_HOST=redis
    ports:
      - "0:8080"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3

  postgres:
    image: postgres:13-alpine
    environment:
      POSTGRES_PASSWORD: test123
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:6-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 3

networks:
  default:
    name: regression-net

volumes:
  pgdata:

看到没?我把 name 显式指定为 snapshot-regression-test,这样无论哪个 CI Job 运行,容器前缀都是固定的,方便后面做快照对比。

3.5 结构验证小技巧

在写 Compose 文件时,我习惯先跑一个 docker compose config 看实际解析结果。这条命令会展开所有变量、合并多个文件,输出最终生效的结构。如果发现有奇怪的报错,八成是 YAML 缩进或字段拼写错了。另外,建议在 CI 里把这个步骤放到快照生成之前,一旦校验失败就直接中断,别让它悄悄跑下去。

🔧 小技巧:用 docker compose --dry-run up 模拟启动,可以提前暴露网络冲突、端口占用等问题。我在项目中加了这行后,快照回归的错误率直接降了 60%。

总之,Compose 文件结构看似简单,但每一层都藏着影响回归测试稳定性的细节。把 version、name、services、networks、volumes 这几个关键块吃透,大部分编译失败、容器跑不起来的问题都能提前拦住。