This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/gyh/docker/docker-compose使用指南.md
T

18 KiB
Raw Blame History

Docker Compose 使用指南

Docker Compose 用 YAML 文件定义多容器应用,一条 docker compose up 启动所有服务。开发环境和生产环境都大量使用。


快速开始(TL;DR)

# 1. 创建 docker-compose.yml
# 2. 启动所有服务
docker compose up -d

# 3. 查看状态
docker compose ps

# 4. 查看日志
docker compose logs -f

# 5. 停止并清理
docker compose down

目录: 基本结构 · 完整示例 · 常用配置 · 多环境 · 常用命令 · 常见问题 · 模板速查 · 格式演进 · 高级配置 · 最佳实践 · 速查卡


一、基本结构

# docker-compose.yml
version: '3.8'

services:
  web:          # 前端/后端应用
  db:           # 数据库
  redis:        # 缓存
  nginx:        # 反向代理

networks:       # 网络定义
volumes:        # 数据卷定义

二、完整示例

2.1 Node.js + MySQL + Redis 全栈项目

version: '3.8'

services:
  # ========== 后端应用 ==========
  api:
    build:
      context: ./server
      dockerfile: Dockerfile
      args:
        NODE_ENV: production
    container_name: my-api
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - DB_PORT=3306
      - DB_USER=root
      - DB_PASSWORD=root123
      - DB_NAME=mydb
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    restart: always
    networks:
      - app-network
    volumes:
      - api-logs:/app/logs

  # ========== 前端应用 ==========
  web:
    build:
      context: ./client
      dockerfile: Dockerfile
    container_name: my-web
    ports:
      - "80:3000"
    depends_on:
      - api
    restart: always
    networks:
      - app-network

  # ========== 数据库 ==========
  db:
    image: mysql:8.0
    container_name: my-db
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: mydb
      MYSQL_USER: admin
      MYSQL_PASSWORD: admin123
    ports:
      - "3306:3306"
    volumes:
      - db-data:/var/lib/mysql
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always
    networks:
      - app-network

  # ========== 缓存 ==========
  redis:
    image: redis:7-alpine
    container_name: my-redis
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes
    restart: always
    networks:
      - app-network

  # ========== 反向代理 ==========
  nginx:
    image: nginx:alpine
    container_name: my-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - web
      - api
    restart: always
    networks:
      - app-network

# ========== 网络 ==========
networks:
  app-network:
    driver: bridge

# ========== 数据卷 ==========
volumes:
  db-data:
  redis-data:
  api-logs:

三、常用配置详解

3.1 build — 从 Dockerfile 构建

services:
  # 方式一:当前目录(自动找 Dockerfile)
  web:
    build: .

  # 方式二:指定上下文和 Dockerfile
  web:
    build:
      context: ./frontend
      dockerfile: Dockerfile.prod

  # 方式三:加构建参数
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NODE_ENV: production
        VERSION: 1.0.0
      target: production     # 多阶段构建指定阶段

  # 方式四:直接用已有镜像(不构建)
  db:
    image: mysql:8.0

3.2 depends_on — 启动顺序

services:
  api:
    depends_on:
      db:
        condition: service_healthy    # 等 db 健康检查通过
      redis:
        condition: service_started    # 等 redis 启动即可

注意: depends_on 只管启动顺序,不管可用性。condition: service_healthy + healthcheck 才能真正等服务就绪。

3.3 healthcheck — 健康检查

services:
  db:
    image: mysql:8.0
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s       # 每 10 秒检查一次
      timeout: 5s         # 超时时间
      retries: 5          # 最多重试 5 次
      start_period: 30s   # 容器启动后等 30 秒才开始检查(给数据库初始化时间)

常见健康检查命令:

服务 健康检查命令
MySQL mysqladmin ping -h localhost
Redis redis-cli ping
Node.js `wget -qO- http://localhost:3000/health
Nginx `curl -f http://localhost/
PostgreSQL pg_isready -h localhost

3.4 environment — 环境变量

# 方式一:列表格式
environment:
  - NODE_ENV=production
  - DB_HOST=db

# 方式二:字典格式(推荐,更易读)
environment:
  NODE_ENV: production
  DB_HOST: db
  DB_PORT: 3306

# 方式三:从 .env 文件加载(最推荐)
env_file:
  - .env.production

# 混合使用
environment:
  NODE_ENV: production
  DB_HOST: db
env_file:
  - .env

3.5 volumes — 数据持久化

volumes:
  # 命名卷(推荐,Docker 管理)
  volumes:
    - db-data:/var/lib/mysql

  # 绑定挂载(绑定到宿主机路径)
  volumes:
    - ./data:/app/data

  # 只读挂载
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro

  # 匿名卷(不需要命名)
  volumes:
    - /tmp/data

3.6 restart — 重启策略

restart: always            # 永远重启(包括手动停止后重启)
restart: on-failure        # 仅失败时重启
restart: unless-stopped    # 除非手动停止,否则重启(推荐)
restart: no                # 不自动重启(默认)

3.7 ports vs expose

ports:
  - "8080:80"              # 宿主端口:容器端口(外部可访问)
  - "127.0.0.1:8080:80"    # 仅本地可访问
  - "3000"                 # 随机端口

expose:
  - "3000"                 # 仅容器间通信,外部不可访问

四、多环境配置

4.1 使用覆盖文件

# docker-compose.yml(基础配置)
services:
  api:
    build: .
    environment:
      - NODE_ENV=development
    volumes:
      - ./server:/app          # 开发时热重载

  db:
    image: mysql:8.0
# docker-compose.prod.yml(生产覆盖)
services:
  api:
    environment:
      - NODE_ENV=production
    # 覆盖开发时的 volume 挂载
    volumes: []                # 生产时不要挂载宿主机目录
# 使用:基础 + 生产覆盖
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

4.2 更简洁的方式(环境变量控制)

# docker-compose.yml
services:
  api:
    build: .
    environment:
      - NODE_ENV=${NODE_ENV:-development}
      - DB_HOST=${DB_HOST:-db}
    volumes:
      - ${MOUNT_VOLUMES:-./server:/app}
# 开发环境(默认)
docker compose up -d

# 生产环境
NODE_ENV=production MOUNT_VOLUMES="" docker compose up -d

五、常用命令

# 启动所有服务(后台)
docker compose up -d

# 启动所有服务(前台,看日志)
docker compose up

# 启动单个服务
docker compose up -d db redis

# 停止所有服务(不删除容器和数据卷)
docker compose stop

# 停止并删除所有容器
docker compose down

# 停止并删除容器、网络
docker compose down --rmi all

# 重建镜像并启动(代码改动后)
docker compose up -d --build

# 重建并重新初始化数据卷
docker compose down -v
docker compose up -d --build

# 查看服务状态
docker compose ps

# 查看服务日志
docker compose logs
docker compose logs -f api        # 只看 api 服务的日志
docker compose logs -f --tail 100 db  # 只看 db 的最后 100 行

# 进入运行中的容器
docker compose exec api bash
docker compose exec db mysql -u root -p

# 执行单次命令
docker compose run api npm run db:migrate
docker compose run --rm web npm test    # --rm 执行完自动删除

# 查看资源占用
docker compose ps

# 构建并启动
docker compose build
docker compose up -d

# 更新镜像
docker compose pull
docker compose up -d --pull always

六、常见问题

6.1 容器间无法互相访问

# 确保所有服务在同一网络下
services:
  api:
    networks: [app-network]
  db:
    networks: [app-network]

networks:
  app-network:
    driver: bridge

默认情况下,Docker Compose 会为同一个 compose 文件创建同一个网络,不同 compose 文件的容器不能互相访问。

6.2 数据库启动慢,应用连不上

services:
  api:
    depends_on:
      db:
        condition: service_healthy   # 健康检查通过才启动

或在应用代码中添加重试逻辑。

6.3 端口冲突

# 查看端口占用
netstat -ano | findstr :3000    # Windows
lsof -i :3000                   # macOS/Linux

修改 docker-compose.yml 中的端口映射:

ports:
  - "3001:3000"    # 宿主机 3001 → 容器 3000

6.4 .env 文件

# 在项目根目录创建 .env 文件
DB_HOST=db
DB_PASSWORD=root123
NODE_ENV=production
COMPOSE_PROJECT_NAME=myapp

Docker Compose 会自动读取当前目录的 .env 文件,无需额外配置。$DB_HOST 在 docker-compose.yml 中会被自动替换。


七、常用模板速查

7.1 纯前端静态站点(Nginx)

services:
  web:
    build: .
    ports:
      - "80:80"
    restart: always

7.2 Node.js + PostgreSQL

services:
  app:
    build: .
    ports: ["3000:3000"]
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s

networks:
volumes:
  pg-data:

7.3 Next.js 全功能模板

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: production
    ports: ["3000:3000"]
    environment:
      - NODE_ENV=production
      - DATABASE_URL=$DATABASE_URL
      - NEXTAUTH_SECRET=$NEXTAUTH_SECRET
    restart: always
    networks: [app-network]

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=app
      - POSTGRES_PASSWORD=$DB_PASSWORD
    volumes: [pg-data:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
    networks: [app-network]

  redis:
    image: redis:7-alpine
    volumes: [redis-data:/data]
    networks: [app-network]

networks:
  app-network:
volumes:
  pg-data:
  redis-data:

八、Compose 文件格式演进

8.1 新版 Compose Specification(推荐)

不再需要 version 字段,Docker Compose V2 起默认使用 Compose Specification 格式:

# 新版写法(推荐)
services:
  app:
    image: node:20-alpine
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production

networks:
  default:
    driver: bridge

volumes:
  data:

关键区别:

  • V3 及以下:必须写 version: '3.8',字段名用点号分隔(如 networks.default)
  • V4 及以上(Compose Specification):不需要 version,字段名用嵌套格式(如 networks: 下的 default:)

8.2 如何判断使用哪种格式

# 查看 Compose 版本
docker compose version

# Compose V2+(2020 年起)→ 使用 Compose Specification 格式
# 使用 `docker compose`(注意是空格,不是连字符)

建议: 新项目直接使用无 version 的新格式,兼容性更好。


九、高级配置

9.1 deploy — 资源限制(适用于 Compose V3+)

services:
  api:
    image: my-api:latest
    deploy:
      replicas: 3                # 副本数(Swarm 模式)
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      update_config:
        parallelism: 1           # 每次更新 1 个容器
        delay: 10s
        order: start-first       # 先启动新再停止旧
      rollback_config:
        parallelism: 1
        delay: 5s
      resources:
        limits:
          cpus: '0.5'            # 最多 0.5 核 CPU
          memory: 512M           # 最多 512MB 内存
        reservations:
          cpus: '0.25'
          memory: 128M

注意: deploy 在 docker compose up(非 Swarm 模式)下部分字段不生效(replicas、update_config 等)。资源限制 limits/reservations 在普通模式下仍然生效。

9.2 profiles — 按需启停服务

services:
  web:
    image: nginx:alpine
    profiles: ["app"]

  db:
    image: postgres:16-alpine
    profiles: ["db", "app"]

  redis:
    image: redis:7-alpine
    profiles: ["cache", "app"]

  monitoring:
    image: grafana/grafana
    profiles: ["monitoring"]
# 启动 app 相关服务(web + db + redis)
docker compose --profile app up -d

# 启动 app + 监控
docker compose --profile app --profile monitoring up -d

# 启动所有带 profile 的服务
docker compose --profile app --profile db --profile cache --profile monitoring up -d

# 启动所有服务(包括无 profile 的)
docker compose up -d

# 查看当前 profile 配置
docker compose config --profiles

场景: 开发时只启动 app,测试时加上 db,生产环境加上 monitoring。

9.3 configs — 配置文件管理

services:
  nginx:
    image: nginx:alpine
    configs:
      - source: nginx_conf
        target: /etc/nginx/conf.d/default.conf
        mode: 0444           # 文件权限

  app:
    image: my-app:latest
    configs:
      - source: app_config
        target: /etc/app/config.yaml
        mode: 0440

configs:
  nginx_conf:
    file: ./configs/nginx.conf
  app_config:
    file: ./configs/app.yaml
    external: false          # 本地文件

适用场景: 需要分发配置文件但不想硬编码到镜像中。

9.4 secrets — 敏感信息管理

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_pass
    secrets:
      - db_root_pass
      - db_config

secrets:
  db_root_pass:
    file: ./secrets/db_root_pass.txt    # 从文件读取
  db_config:
    string: '{"max_connections": 100}'  # 直接写字符串

安全建议: 敏感信息不要写死在 docker-compose.yml 中,使用 secrets 或 .env 文件管理。

9.5 其他实用配置

services:
  app:
    image: node:20-alpine

    # 指定运行用户
    user: "1000:1000"

    # 工作目录
    working_dir: /app

    # 覆盖默认入口点和命令
    entrypoint: ["node"]
    command: ["server.js"]

    # 容器别名(同一 compose 内通过别名访问)
    container_name: my-app

    # 标签(元数据)
    labels:
      - "com.example.description=API Server"
      - "com.example.environment=production"

    # 时区
    environment:
      - TZ=Asia/Shanghai

    # 挂载共享内存(深度学习场景)
    shm_size: '2gb'

    # 安全选项
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

十、最佳实践

10.1 安全性

# ✅ 使用非 root 用户
user: "1000:1000"

# ✅ 最小化权限
cap_drop:
  - ALL
security_opt:
  - no-new-privileges:true

# ✅ 敏感信息用 secrets 或 .env
secrets:
  - db_password

# ❌ 避免使用 privileged
# privileged: true

# ❌ 避免绑定 0.0.0.0
# ports:
#   - "0.0.0.0:3000:3000"

10.2 可靠性

# ✅ 所有外部依赖都加 healthcheck
db:
  healthcheck:
    test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
    start_period: 30s

# ✅ 合理的重启策略
restart: unless-stopped

# ✅ 依赖顺序用 condition
depends_on:
  db:
    condition: service_healthy

10.3 可维护性

# ✅ 使用 .env 管理变量
# .env
COMPOSE_PROJECT_NAME=myapp
MYSQL_ROOT_PASSWORD=xxxxx
NODE_ENV=production

# docker-compose.yml
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql

# ✅ 命名卷而不是绑定挂载(数据持久化)
volumes:
  db-data:    # Docker 管理,更安全

# ✅ 用 profiles 组织服务
# 开发只启动 app + db
# docker compose --profile dev up -d

10.4 性能优化

# ✅ 生产环境使用 Alpine 镜像
image: node:20-alpine        # 约 150MB
# vs
image: node:20               # 约 1GB

# ✅ 限制资源使用
deploy:
  resources:
    limits:
      cpus: '0.5'
      memory: 512M

# ✅ 只暴露必要的端口
# ❌ 数据库不要暴露到宿主机
# db:
#   ports:
#     - "3306:3306"           # 删除这行

# ✅ 使用 expose 代替 ports(容器间通信)
db:
  expose:
    - "3306"

十一、快速参考卡

字段 用途 示例
image 使用已有镜像 image: nginx:alpine
build 从 Dockerfile 构建 build: ./app
ports 端口映射(外部可访问) "80:80"
expose 端口暴露(仅容器间) "3000"
volumes 数据持久化 data:/var/lib/mysql
environment 环境变量 NODE_ENV: production
depends_on 启动依赖 db: condition: service_healthy
healthcheck 健康检查 test: ["CMD", "curl", ...]
restart 重启策略 unless-stopped
networks 网络归属 app-network
profiles 按需启停 ["dev", "monitoring"]
secrets 敏感信息管理 file: ./secrets/xxx
configs 配置文件管理 target: /etc/app/config
deploy.resources 资源限制 cpus: '0.5', memory: 512M
container_name 固定容器名 my-container
user 运行用户 "1000:1000"