Skip to content
Docker Compose

Docker Compose

Docker Compose 使用 YAML 文件定义和管理多容器应用,实现一键启动、停止和编排。


概述

# docker-compose.yaml
services:
  web:
    build: .
    ports:
      - "8080:80"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
# 启动所有服务
docker compose up -d 

# 查看日志
docker compose logs -f

# 停止并删除容器和网络(不删除卷)
docker compose down

# 停止并删除包括卷
docker compose down -v

💡 Docker Compose V2docker compose,无连字符)已取代 V1(docker-compose)。V2 是 Docker CLI 的插件,用 Go 重写,性能更好。


Compose 文件结构

完整文件布局

version: "3.8"       # ⚠️ 已弃用:Docker Compose V2 不再需要此字段

name: my_project      # 项目名称(V2.0+)

services:             # 服务定义(容器)
  app:
    ...

networks:             # 自定义网络
  frontend:
    ...

volumes:              # 自定义卷
  db_data:
    ...

configs:              # 配置(Swarm 模式)
  app_config:
    ...

secrets:              # 密钥(Swarm 模式)
  db_password:
    ...

🚨 注意version 字段在 Compose V2 中已弃用,写不写都一样。新项目建议省略。


Services 详解

build — 从 Dockerfile 构建

services:
  app:
    build:
      context: ./app           # 构建上下文目录
      dockerfile: Dockerfile.prod  # Dockerfile 文件名
      args:                    # 构建参数(ARG)
        APP_VERSION: "1.0"
        NODE_ENV: production
      cache_from:              # 外部缓存源
        - my_app:latest
      labels:
        - "com.example.build=true"
    image: my_app:1.0          # 构建后给镜像打标签

image — 使用已有镜像

services:
  redis:
    image: redis:7-alpine
  custom:
    image: my-registry.example.com/my_app:latest

💡 同时使用 buildimagebuild 指定如何构建,image 指定构建后的镜像名称/标签。

ports — 端口映射

services:
  app:
    ports:
      - "8080:80"               # 短语法:宿主机:容器
      - "192.168.1.100:8081:81"  # 绑定到特定 IP
      - target: 443             # 长语法
        published: 8443
        protocol: tcp
        mode: host

volumes — 挂载卷

services:
  db:
    volumes:
      - db_data:/var/lib/mysql            # 命名卷(短语法)
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro  # 绑定挂载 + 只读
      - type: bind                         # 长语法
        source: ./data
        target: /app/data
        consistency: cached
      - type: tmpfs                        # 内存临时卷
        target: /app/cache
        tmpfs:
          size: 128M

environment / env_file — 环境变量

services:
  app:
    environment:
      DB_HOST: postgres
      DB_PORT: "5432"
      REDIS_URL: redis://redis:6379

    # 或者从文件加载
    env_file:
      - .env
      - .env.production

    # 单独设置某个变量(覆盖 env_file 中的值)
    environment:
      - NODE_ENV=production

💡 优先级:命令行 --env > Compose 文件 environment > env_file > 镜像默认值。

depends_on — 启动顺序

services:
  web:
    depends_on:
      - db
      - redis

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  web_with_condition:
    depends_on:
      db:
        condition: service_healthy    # 等 db 健康后才启动
      redis:
        condition: service_started    # redis 启动即开始(默认)
条件 说明
service_started 依赖服务启动即可(默认)
service_healthy 依赖服务健康检查通过
service_completed_successfully 依赖服务执行完毕且退出码为 0(一次性任务)

🚨 陷阱depends_on 只控制启动顺序,不保证依赖服务内部的应用程序已就绪。必须配合 healthcheck + condition: service_healthy 才能真正等待就绪。

健康检查

services:
  api:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s          # 启动缓冲期

restart — 重启策略

services:
  app:
    restart: unless-stopped
说明
no 不自动重启(默认)
always 无论退出码,总是重启
on-failure 仅非正常退出时重启
unless-stopped 除非手动 docker compose stop,否则始终重启

资源限制

services:
  app:
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 512M
        reservations:
          cpus: "0.5"
          memory: 256M

⚠️ 从 Compose V2 开始,deploy.resources非 Swarm 模式下也生效。

extra_hosts — 自定义 hosts

services:
  app:
    extra_hosts:
      - "internal.service:192.168.1.100"
      - "auth.local:10.0.0.1"

profiles — 条件启动

services:
  app:
    profiles: ["production"]   # 默认不启动

  debug:
    profiles: ["debug"]        # 默认不启动

  db:
    # 没有 profiles,始终启动
# 默认只启动 db
docker compose up -d

# 启动 production profile
docker compose --profile production up -d

# 启动多个 profile
docker compose --profile production --profile debug up -d

网络配置

services:
  web:
    networks:
      - frontend
      - backend

  api:
    networks:
      - backend

  db:
    networks:
      - backend

networks:
  frontend:                    # 使用默认 driver(bridge)
  backend:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: br_backend
    ipam:
      config:
        - subnet: 172.28.0.0/16

Docker Compose 会自动为每个项目创建一个网络,项目中的服务默认能通过服务名互相访问。


extends — 继承配置

# docker-compose.base.yaml
services:
  app_base:
    build: .
    environment:
      LOG_LEVEL: info
    restart: unless-stopped

# docker-compose.yaml
services:
  web:
    extends:
      file: docker-compose.base.yaml
      service: app_base
    ports:
      - "8080:80"
    environment:
      SERVICE_NAME: web     # 会覆盖或合并 base 中的值

  worker:
    extends:
      file: docker-compose.base.yaml
      service: app_base
    environment:
      SERVICE_NAME: worker

configs 和 secrets(Swarm)

services:
  app:
    secrets:
      - db_password
      - source: api_key
        target: /run/secrets/api_key.txt
        mode: 0400

    configs:
      - app_config

secrets:
  db_password:
    file: ./secrets/db_password.txt

configs:
  app_config:
    file: ./config/production.yaml

CLI 常用命令

# 构建/重建镜像
docker compose build
docker compose build --no-cache web

# 启动
docker compose up -d                     # 后台启动所有服务
docker compose up -d web api             # 只启动指定服务
docker compose up --scale web=3          # 启动 3 个 web 实例(需去除端口冲突)

# 查看
docker compose ps                        # 查看服务状态
docker compose logs -f                   # 实时日志
docker compose logs -f web               # 指定服务
docker compose top                       # 查看进程
docker compose images                    # 列出镜像

# 停止/删除
docker compose stop                      # 停止服务
docker compose down                      # 停止并删除容器和网络
docker compose down -v                   # 也包括卷
docker compose down --rmi all            # 也包括镜像

# 在服务中执行命令
docker compose exec web sh
docker compose exec db psql -U postgres

# 其他
docker compose restart                   # 重启服务
docker compose pull                      # 拉取最新镜像
docker compose config                    # 验证并查看合并后的配置
docker compose convert                   # 将 Compose 文件转换为平台 API 格式

💡 最佳实践:使用 docker compose config 验证 Compose 文件是否有语法错误,查看环境变量替换后的最终配置。


环境变量替换

services:
  app:
    image: ${REGISTRY:-docker.io}/my_app:${TAG:-latest}
    ports:
      - "${PORT:-8080}:3000"
# 默认环境变量来自:
#   1. Shell 环境变量
#   2. .env 文件(与 docker-compose.yaml 同目录)
#   3. --env-file 指定的文件

# .env 文件示例
REGISTRY=my-registry.example.com
TAG=1.0.5
PORT=80

典型模板

前后端分离项目

services:
  nginx:
    image: nginx:1.25-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - api
    restart: unless-stopped
    networks:
      - frontend

  api:
    build: ./api
    environment:
      DB_HOST: db
      REDIS_HOST: redis
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped
    networks:
      - frontend
      - backend

  worker:
    build: ./worker
    environment:
      DB_HOST: db
      REDIS_HOST: redis
    restart: unless-stopped
    networks:
      - backend

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      retries: 5
    restart: unless-stopped
    networks:
      - backend

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data
    restart: unless-stopped
    networks:
      - backend

networks:
  frontend:
  backend:
    internal: true   # 内部网络,不与外部通信

volumes:
  pgdata:
  redisdata:

开发环境配置

# docker-compose.dev.yaml
services:
  api:
    build:
      context: ./api
      target: development
    volumes:
      - ./api/src:/app/src   # 代码热加载
    environment:
      - NODE_ENV=development
    ports:
      - "9229:9229"           # 调试端口
    command: npm run dev

常见陷阱

陷阱 说明 正确做法
depends_on 不等待就绪 只等容器启动,不等应用就绪 配合 healthcheck + condition: service_healthy
忘记 .env 中的变量 变量未设置时 Compose 报错 使用 ${VAR:-default} 提供默认值
卷数据残留 docker compose down 不删除卷 需要时使用 -v 参数
端口冲突 多个副本 scale 时端口冲突 只 scale 不映射端口或使用动态端口
忽视网络隔离 所有服务在同一个网络 使用 frontend/backend 网络分层
Compose V1/V2 混用 docker-composedocker compose 行为略有不同 统一使用 V2