返回博客

Docker Compose 最佳实践

Docker Compose 是定义和运行多容器应用的工具。通过一个 YAML 文件配置所有服务,一条命令就能启动整个应用栈。本文分享 Docker Compose 的最佳实践,帮助你构建可维护、可扩展的容器化应用。

核心价值:统一配置管理、一键启动/停止、服务依赖编排、网络自动配置、数据持久化。

一、基础结构

compose.yaml 文件结构

# compose.yaml (或 docker-compose.yml)
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
    depends_on:
      - api
  
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
  
  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: example

volumes:
  pgdata:

networks:
  default:
    name: myapp-network

版本选择

# 现代 Docker Compose 不需要 version 字段
# 旧格式(已废弃):
# version: '3.8'

# 当前最佳实践:直接定义 services
services:
  app:
    image: myapp
注意version 字段在 Docker Compose V2 中已废弃,不再需要指定。

二、服务定义最佳实践

1. 使用 build 而非 image(开发环境)

services:
  app:
    build:
      context: ./app          # 构建上下文
      dockerfile: Dockerfile  # Dockerfile 名称
      args:
        NODE_VERSION: 20      # 构建参数
    ports:
      - "3000:3000"

2. 合理命名服务

# 使用清晰的服务名
services:
  frontend:      # 前端
  backend-api:   # 后端 API
  backend-worker: # 后台任务
  database:      # 数据库
  cache:         # 缓存
  queue:         # 消息队列

3. 端口映射规范

services:
  web:
    ports:
      # 格式:"HOST_PORT:CONTAINER_PORT"
      - "80:80"       # 标准 HTTP
      - "443:443"     # 标准 HTTPS
      
      # 只指定容器端口(随机主机端口)
      - "3000"
      
      # 指定 IP 和端口
      - "127.0.0.1:8000:8000"  # 只本地访问
安全建议:数据库等服务只绑定到 127.0.0.1,避免外部访问:- "127.0.0.1:5432:5432"

三、网络配置

默认网络

# 所有服务自动加入默认网络
# 服务间可通过服务名互相访问
services:
  api:
    # 可直接访问 db:5432
  db:
    # 可直接访问 api:3000

自定义网络

services:
  frontend:
    networks:
      - public
      
  backend:
    networks:
      - public
      - private
      
  database:
    networks:
      - private  # 只能被 backend 访问

networks:
  public:
    name: app-public
  private:
    name: app-private
    internal: true  # 无法访问外部网络

网络别名

services:
  db:
    networks:
      default:
        aliases:
          - database
          - postgres
    # 其他服务可以用 db、database 或 postgres 访问

四、数据持久化

命名卷(推荐)

services:
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data  # 命名卷

volumes:
  pgdata:
    name: myapp-pgdata  # 自定义名称

绑定挂载(开发环境)

services:
  app:
    volumes:
      - ./src:/app/src          # 代码同步
      - ./config:/app/config:ro # 只读配置
      
      # 匿名卷(临时数据)
      - /app/tmp
生产环境警告:避免使用绑定挂载(./path),使用命名卷更可靠。

卷驱动配置

volumes:
  pgdata:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/postgres

五、环境变量管理

方式一:直接定义

services:
  app:
    environment:
      - NODE_ENV=production
      - DEBUG=false

方式二:使用 env_file

services:
  app:
    env_file:
      - .env              # 默认环境变量
      - .env.production   # 生产环境覆盖
      
# .env 文件
NODE_ENV=production
DB_HOST=db
DB_PORT=5432

方式三:从宿主机传递

services:
  app:
    environment:
      - NODE_ENV=${NODE_ENV}  # 从宿主机 .env 读取
      - API_KEY=${API_KEY:-default}  # 默认值
安全警告:敏感信息(密码、密钥)不要直接写在 compose.yaml,使用环境变量或 secrets。

六、健康检查

services:
  web:
    image: nginx
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s      # 检查间隔
      timeout: 10s       # 超时时间
      retries: 3         # 重试次数
      start_period: 40s  # 启动等待
      
  db:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

依赖健康状态

services:
  api:
    depends_on:
      db:
        condition: service_healthy  # 等待 db 健康
      cache:
        condition: service_started  # 只等待启动

七、资源限制

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '0.5'      # 最大 CPU
          memory: 512M     # 最大内存
        reservations:
          cpus: '0.25'     # 保留 CPU
          memory: 256M     # 保留内存
    
    # 或使用旧格式(单容器)
    mem_limit: 512m
    cpus: 0.5

八、常用命令

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

# 停止所有服务
docker compose down

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

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f app

# 进入容器
docker compose exec app bash

# 重新构建
docker compose build --no-cache

# 拉取所有镜像
docker compose pull

# 验证配置
docker compose config

# 查看服务进程
docker compose top

九、多环境配置

使用多个 compose 文件

# compose.yaml(基础配置)
services:
  app:
    image: myapp
    ports:
      - "3000:3000"

# compose.prod.yaml(生产覆盖)
services:
  app:
    image: myapp:v1.0
    environment:
      - NODE_ENV=production
    deploy:
      replicas: 3

# 启动生产环境
docker compose -f compose.yaml -f compose.prod.yaml up -d

使用 override 文件

# compose.override.yaml 自动合并
# Docker Compose 自动加载 compose.yaml + compose.override.yaml

services:
  app:
    build: ./app  # 开发环境本地构建
    volumes:
      - ./src:/app/src  # 代码热更新

十、最佳实践总结