Skip to content

docker-compose.yml 结构与关键特性:从开发到生产的工程化实践

docker-compose.yml 是定义多服务应用的声明式配置文件,它让开发者能够以简洁的 YAML 语法描述复杂的服务拓扑、网络、存储和安全策略。掌握其核心结构与高级特性,是构建可维护、安全、环境一致的容器化应用的关键。

一、基本结构:服务(services)、网络(networks)、卷(volumes)、密钥(secrets)

一个典型的 docker-compose.yml 包含以下顶级字段:

yaml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=secret
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

volumes:
  db-data:

networks:
  app-network:
    driver: bridge

二、关键特性详解

1. depends_on:控制服务启动顺序

作用:确保一个服务在另一个服务启动之后才开始启动。

示例

yaml
depends_on:
  - db

局限性

  • 仅保证启动顺序,不等待服务“就绪”
    即:web 服务会在 db 容器启动后启动,但此时 PostgreSQL 可能仍在初始化,尚未接受连接,导致 web 启动失败。

解决方案:必须配合 healthcheck 使用。

2. healthcheck:判断服务是否真正就绪

作用:通过定期执行命令检测服务健康状态,Docker 将服务标记为 healthyunhealthy

语法

yaml
healthcheck:
  test: ["CMD-SHELL", "pg_isready -U postgres"]  # 检查 PostgreSQL
  interval: 10s    # 每 10 秒检查一次
  timeout: 5s      # 超时 5 秒
  retries: 5       # 失败 5 次后标记为 unhealthy
  start_period: 30s # 容器启动后 30 秒内不检查

常用健康检查命令

服务健康检查命令
PostgreSQLpg_isready -U postgres
MySQLmysqladmin ping -h localhost -u root -p$MYSQL_ROOT_PASSWORD
Redisredis-cli ping
Node.js APIcurl -f http://localhost:3000/health || exit 1

depends_on 结合使用(Compose v2.1+ 支持 condition: service_healthy):

yaml
depends_on:
  db:
    condition: service_healthy

这样,web 服务将等待 db 进入 healthy 状态后才启动,彻底解决“启动顺序但未就绪”问题。

3. networks:自定义网络,服务间通信

作用:创建隔离的网络环境,服务可通过服务名(service name)直接通信。

示例

yaml
networks:
  app-network:
    driver: bridge

服务间通信

  • web 服务可通过 http://db:5432 访问数据库
  • 无需暴露端口到主机,提升安全性
  • 自动 DNS 解析,无需手动配置 IP

优势

  • 网络隔离,避免端口冲突
  • 支持自定义驱动(如 overlay 用于 Swarm)
  • 服务发现简单可靠

4. secretsconfigs:安全注入敏感数据与配置

secrets:安全传递密码、密钥等敏感信息
yaml
services:
  web:
    image: myapp
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt
    # 或 external: true(从 Swarm/K8s 获取)

在应用中通过 /run/secrets/db_password 读取:

js
const password = fs.readFileSync('/run/secrets/db_password', 'utf8');
configs:注入非敏感配置文件(如 Nginx 配置、TLS 证书)
yaml
services:
  web:
    configs:
      - nginx_config

configs:
  nginx_config:
    file: ./config/nginx.conf

优势

  • 避免将密码硬编码在 environment.env 文件中
  • 支持 Docker Swarm 和 Kubernetes 集成
  • 生产环境更安全

三、开发 vs 生产配置:多文件覆盖模式

docker-compose 支持使用多个 YAML 文件,后加载的文件会覆盖或合并前一个文件的配置,非常适合区分环境。

1. 开发配置:docker-compose.dev.yml

yaml
# docker-compose.dev.yml
version: '3.8'
services:
  web:
    build: .
    volumes:
      - .:/app              # 挂载源码,热更新
      - /app/node_modules   # 忽略容器内 node_modules
    command: npm run dev    # 启动开发服务器
    environment:
      - NODE_ENV=development
    ports:
      - "9229:9229"         # 开启调试端口

2. 生产配置:docker-compose.prod.yml

yaml
# docker-compose.prod.yml
version: '3.8'
services:
  web:
    image: myapp:latest      # 使用预构建镜像
    command: npm start
    environment:
      - NODE_ENV=production
    ports: []
    # 移除 volumes,禁止 shell 访问
    # 可添加 replicas、resources 限制

3. 合并启动

bash
# 开发环境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# 生产环境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

执行逻辑

  • 先加载基础配置(docker-compose.yml
  • 再加载环境特定配置,覆盖相关字段
  • 最终生成一个合并后的服务定义

四、最佳实践总结

特性推荐用法
depends_on必须配合 healthcheck 使用,避免启动失败
healthcheck所有依赖服务(DB、Redis)都应配置
networks所有服务使用自定义网络,通过服务名通信
secrets生产环境注入数据库密码、JWT 密钥等
configs注入 Nginx、Logrotate 等配置文件
多文件配置base.yml + dev.yml / prod.yml 分离环境

五、结语

docker-compose.yml 不只是一个“启动多个容器”的工具,它是一个完整的应用编排平台。通过合理使用 healthchecknetworkssecrets 和多文件覆盖模式,你可以构建出:

  • 开发友好:热更新、调试端口、交互式 shell
  • 生产安全:非 root 用户、无敏感信息、资源限制
  • 环境一致:开发、预发、生产配置统一管理

这才是现代全栈开发应有的工程化水平。