Skip to content

Docker Compose 文件参考

Docker Compose 文件(docker-compose.yml)是定义多容器应用的核心配置文件。本文将详细介绍 Compose 文件的完整语法和配置选项。

目录

  1. 文件格式
  2. 服务配置
  3. 网络配置
  4. 卷配置
  5. 配置和密钥
  6. 扩展字段

文件格式

1.1 版本说明

yaml
# Compose 文件版本
version: '3.8'  # 推荐版本

# 版本演进:
# - 1.x: 旧版格式
# - 2.x: 支持网络、卷
# - 3.x: 支持 Swarm 部署

1.2 文件结构

yaml
version: '3.8'

services:
  # 服务定义

networks:
  # 网络定义

volumes:
  # 卷定义

configs:
  # 配置定义

secrets:
  # 密钥定义

1.3 多文件配置

yaml
# docker-compose.yml (基础配置)
version: '3.8'
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"

# docker-compose.override.yml (自动加载,开发环境)
version: '3.8'
services:
  web:
    volumes:
      - ./html:/usr/share/nginx/html

# docker-compose.prod.yml (生产环境)
version: '3.8'
services:
  web:
    deploy:
      replicas: 3

服务配置

2.1 基本服务配置

yaml
services:
  web:
    # 镜像或构建
    image: nginx:alpine
    # 或
    build:
      context: ./web
      dockerfile: Dockerfile.prod
    
    # 容器名称
    container_name: my-web
    
    # 主机名
    hostname: web
    
    # 域名
    domainname: example.com
    
    # 用户名/UID
    user: "1000:1000"
    
    # 工作目录
    working_dir: /app
    
    # 入口点
    entrypoint: ["/app/entrypoint.sh"]
    
    # 命令
    command: ["nginx", "-g", "daemon off;"]
    
    # 环境变量
    environment:
      - NODE_ENV=production
      - DEBUG=1
    
    # 环境变量文件
    env_file:
      - .env
      - .env.local

2.2 端口映射

yaml
services:
  web:
    # 短语法
    ports:
      - "3000"           # 只暴露容器端口(随机主机端口)
      - "8080:80"        # 主机:容器
      - "127.0.0.1:8080:80"  # 绑定地址
      - "127.0.0.1:8080-8090:80-90"  # 范围
      - "8080:80/udp"    # 指定协议
    
    # 长语法(推荐)
    ports:
      - target: 80
        published: 8080
        protocol: tcp
        mode: host
      
      - target: 443
        published: 8443
        protocol: tcp
        mode: host

2.3 卷挂载

yaml
services:
  web:
    # 短语法
    volumes:
      - /var/lib/mysql                    # 命名卷
      - /opt/data:/var/lib/mysql          # 绑定挂载
      - ./cache:/tmp/cache:ro             # 只读
      - data-volume:/var/lib/mysql        # 使用命名卷
    
    # 长语法(推荐)
    volumes:
      - type: volume
        source: mydata
        target: /data
        volume:
          nocopy: true
      
      - type: bind
        source: ./config
        target: /config
        read_only: true
      
      - type: tmpfs
        target: /tmp
        tmpfs:
          size: 100M
          mode: 1770

2.4 网络配置

yaml
services:
  web:
    # 连接网络
    networks:
      - frontend
      - backend
    
    # 网络别名
    networks:
      frontend:
        aliases:
          - web-alias
      backend:
        aliases:
          - api-server
    
    # 静态 IP
    networks:
      frontend:
        ipv4_address: 172.16.238.10
        ipv6_address: 2001:3984:3989::10
    
    # DNS 配置
    dns:
      - 8.8.8.8
      - 8.8.4.4
    dns_search:
      - example.com
    dns_opt:
      - ndots:2
    
    # 额外主机
    extra_hosts:
      - "database:192.168.1.100"
      - "cache:192.168.1.101"
    
    # 主机网络模式
    network_mode: host
    # 或
    network_mode: "service:service_name"
    # 或
    network_mode: "container:container_name"

2.5 依赖关系

yaml
services:
  web:
    # 简单依赖(只控制启动顺序)
    depends_on:
      - db
      - redis
    
    # 带条件的依赖(Compose v3+)
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    
    # 链接(已弃用,使用网络代替)
    links:
      - "db:database"
      - "redis"

2.6 健康检查

yaml
services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
      disable: false
    
    # 或使用命令字符串
    healthcheck:
      test: "curl -f http://localhost:8080/health || exit 1"
      interval: 30s
      timeout: 10s
      retries: 3

2.7 资源限制

yaml
services:
  web:
    # 部署配置(Swarm 模式)
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
          pids: 100
        reservations:
          cpus: '0.25'
          memory: 256M
      
      # 重启策略
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      
      # 更新配置
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
        order: start-first
      
      # 回滚配置
      rollback_config:
        parallelism: 1
        delay: 10s
        failure_action: pause
      
      # 副本数
      replicas: 3
      
      # 放置约束
      placement:
        constraints:
          - node.role == worker
          - node.labels.zone == public
        preferences:
          - spread: node.labels.rack
      
      # 模式
      mode: replicated  # 或 global
    
    # 非 Swarm 模式的资源限制
    mem_limit: 512m
    memswap_limit: 1g
    mem_reservation: 256m
    cpus: '0.5'
    cpu_shares: 512
    cpu_quota: 50000
    cpu_period: 100000
    cpuset: '0,1'

2.8 日志配置

yaml
services:
  web:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "production_status"
        env: "OS_VERSION"
    
    # 或使用其他驱动
    logging:
      driver: syslog
      options:
        syslog-address: "tcp://192.168.0.42:123"
    
    # 禁用日志
    logging:
      driver: none

2.9 安全配置

yaml
services:
  web:
    # 只读根文件系统
    read_only: true
    
    # 用户
    user: "1000:1000"
    
    # 组
    group_add:
      - mail
    
    # 安全选项
    security_opt:
      - no-new-privileges:true
      - seccomp:unconfined
      - apparmor:docker-default
    
    # 能力
    cap_add:
      - NET_ADMIN
    cap_drop:
      - ALL
    
    # 特权模式
    privileged: false
    
    # 设备
    devices:
      - "/dev/ttyUSB0:/dev/ttyUSB0"
    
    # 系统控制
    sysctls:
      - net.core.somaxconn=1024
      - net.ipv4.ip_forward=1
    
    # ulimit
    ulimits:
      nproc: 65535
      nofile:
        soft: 20000
        hard: 40000

2.10 构建配置

yaml
services:
  web:
    build:
      # 构建上下文
      context: ./web
      
      # Dockerfile 路径
      dockerfile: Dockerfile.prod
      
      # 构建参数
      args:
        - NODE_ENV=production
        - VERSION=1.0.0
      
      # 缓存源
      cache_from:
        - myapp/web:latest
        - myapp/web:cache
      
      # 标签
      labels:
        - "com.example.description=Web application"
        - "com.example.department=IT"
      
      # 目标(多阶段构建)
      target: production
      
      # 网络
      network: host
      
      # 秘密
      secrets:
        - npmrc
      
      # SSH
      ssh:
        - default
      
      # 额外主机
      extra_hosts:
        - "npm.registry:192.168.1.100"
      
      # 隔离
      isolation: default

2.11 其他配置

yaml
services:
  web:
    # 暴露端口(不发布到主机)
    expose:
      - "3000"
      - "8080"
    
    # 外部连接
    external_links:
      - redis_1
      - project_db_1:mysql
    
    # PID 模式
    pid: host
    
    # IPC 模式
    ipc: host
    # 或
    ipc: "service:service_name"
    # 或
    ipc: "shareable"
    
    # cgroup 模式
    cgroup: host
    
    # 初始化进程
    init: true
    
    # 标准输入
    stdin_open: true
    
    # 伪终端
    tty: true
    
    # 环境
    environment:
      - TERM=xterm-256color
    
    # 停止信号
    stop_signal: SIGTERM
    
    # 停止超时
    stop_grace_period: 30s
    
    # 重启
    restart: unless-stopped
    # always, on-failure, unless-stopped, no
    
    # 标签
    labels:
      - "com.example.service=web"
      - "com.example.environment=production"
    
    # 设备 cgroup 规则
    device_cgroup_rules:
      - "c 1:3 mr"
      - "a 7:* rmw"

网络配置

3.1 网络定义

yaml
networks:
  # 基本网络
  frontend:
    driver: bridge
  
  # 高级配置
  backend:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: backend-bridge
      com.docker.network.bridge.enable_icc: "true"
      com.docker.network.bridge.enable_ip_masquerade: "true"
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/16
          ip_range: 172.28.5.0/24
          gateway: 172.28.5.254
          aux_addresses:
            host1: 172.28.1.5
            host2: 172.28.1.6
      options:
        foo: bar
    internal: true
    attachable: true
    labels:
      - "com.example.description=Backend network"
  
  # 外部网络
  existing-network:
    external: true
    name: my-pre-existing-network
  
  # Overlay 网络(Swarm)
  overlay-network:
    driver: overlay
    attachable: true
    driver_opts:
      encrypted: "true"

卷配置

4.1 卷定义

yaml
volumes:
  # 基本卷
  db-data:
    driver: local
  
  # 高级配置
  app-data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.100,rw
      device: ":/path/to/dir"
    labels:
      - "com.example.description=Application data"
  
  # 外部卷
  existing-volume:
    external: true
    name: my-pre-existing-volume
  
  # 命名卷
  named-volume:
    driver: local
    driver_opts:
      size: 10GiB

配置和密钥

5.1 配置(Configs)

yaml
configs:
  # 文件配置
  nginx-config:
    file: ./nginx.conf
    labels:
      - "com.example.description=Nginx configuration"
  
  # 外部配置
  external-config:
    external: true
    name: my-pre-existing-config
  
  # 环境变量配置
  env-config:
    environment: CONFIG_DATA
    labels:
      - "com.example.description=Environment config"

services:
  web:
    image: nginx:alpine
    configs:
      - source: nginx-config
        target: /etc/nginx/nginx.conf
        uid: '0'
        gid: '0'
        mode: 0440

5.2 密钥(Secrets)

yaml
secrets:
  # 文件密钥
  db-password:
    file: ./secrets/db-password.txt
    labels:
      - "com.example.description=Database password"
  
  # 外部密钥
  external-secret:
    external: true
    name: my-pre-existing-secret
  
  # 环境变量密钥
  env-secret:
    environment: SECRET_DATA

services:
  db:
    image: postgres:15-alpine
    secrets:
      - source: db-password
        target: /run/secrets/db-password
        uid: '0'
        gid: '0'
        mode: 0400
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db-password

扩展字段

6.1 扩展字段(x-)

yaml
# 定义可复用的扩展字段
x-common-variables: &common-variables
  TZ: Asia/Shanghai
  LANG: en_US.UTF-8

x-common-deploy: &common-deploy
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3

services:
  web:
    image: nginx:alpine
    environment:
      <<: *common-variables
      NGINX_HOST: localhost
    deploy:
      <<: *common-deploy
      replicas: 3
  
  api:
    image: myapi:latest
    environment:
      <<: *common-variables
      API_PORT: 8080
    deploy:
      <<: *common-deploy
      replicas: 2

6.2 环境变量插值

yaml
version: '3.8'

services:
  web:
    image: "${WEB_IMAGE:-nginx:alpine}"
    ports:
      - "${WEB_PORT:-80}:80"
    environment:
      - NODE_ENV=${NODE_ENV:-production}
      - DEBUG=${DEBUG:-false}
    deploy:
      replicas: ${REPLICAS:-1}
    
    # 必需变量
    environment:
      - DATABASE_URL=${DATABASE_URL:?DATABASE_URL is required}

6.3 条件配置

yaml
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    ${PRODUCTION:+deploy:}
      ${PRODUCTION:+replicas: 3}
      ${PRODUCTION:+restart_policy:}
        ${PRODUCTION:+condition: any}

完整示例

yaml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    hostname: nginx
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
    volumes:
      - type: bind
        source: ./nginx/nginx.conf
        target: /etc/nginx/nginx.conf
        read_only: true
      - type: bind
        source: ./nginx/ssl
        target: /etc/nginx/ssl
        read_only: true
      - type: volume
        source: nginx-cache
        target: /var/cache/nginx
    networks:
      - frontend
    depends_on:
      - web
      - api
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
        reservations:
          cpus: '0.25'
          memory: 128M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    logging:
      driver: json-file
      options:
        max-size: 10m
        max-file: 3
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nginx.rule=Host(`example.com`)"

  web:
    build:
      context: ./web
      dockerfile: Dockerfile
      args:
        - NODE_ENV=production
      target: production
    image: myapp/web:${VERSION:-latest}
    environment:
      - NODE_ENV=production
      - API_URL=http://api:8080
      - REDIS_URL=redis://redis:6379
    volumes:
      - type: tmpfs
        target: /tmp
        tmpfs:
          size: 100M
    networks:
      - frontend
      - backend
    depends_on:
      api:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
        order: start-first
      restart_policy:
        condition: any
        delay: 5s
        max_attempts: 3
        window: 120s
      placement:
        constraints:
          - node.role == worker
        preferences:
          - spread: node.labels.zone

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    image: myapp/api:${VERSION:-latest}
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=app
      - DB_USER=api
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    secrets:
      - source: db-password
        target: /run/secrets/db-password
        mode: 0400
    networks:
      - backend
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: api
      POSTGRES_DB: app
      POSTGRES_INITDB_ARGS: --encoding=UTF-8
      PGDATA: /var/lib/postgresql/data/pgdata
    secrets:
      - source: db-password
        target: /run/secrets/db-password
        mode: 0400
    volumes:
      - type: volume
        source: db-data
        target: /var/lib/postgresql/data
      - type: bind
        source: ./db/init
        target: /docker-entrypoint-initdb.d
        read_only: true
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U api -d app"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    deploy:
      placement:
        constraints:
          - node.role == manager
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - type: volume
        source: redis-data
        target: /data
    networks:
      - backend
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M

networks:
  frontend:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: frontend
    labels:
      - "com.example.description=Frontend network"
  
  backend:
    driver: bridge
    internal: true
    driver_opts:
      com.docker.network.bridge.name: backend
      com.docker.network.bridge.enable_icc: "true"
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1
    labels:
      - "com.example.description=Backend network"

volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/db
    labels:
      - "com.example.description=Database data"
  
  redis-data:
    driver: local
  
  nginx-cache:
    driver: local

secrets:
  db-password:
    file: ./secrets/db-password.txt
    labels:
      - "com.example.description=Database password"

下一步

基于 MIT 许可发布