# Docker Compose 使用指南 > Docker Compose 用 **YAML 文件**定义多容器应用,一条 `docker compose up` 启动所有服务。**开发环境和生产环境都大量使用。** --- ## 快速开始(TL;DR) ```bash # 1. 创建 docker-compose.yml # 2. 启动所有服务 docker compose up -d # 3. 查看状态 docker compose ps # 4. 查看日志 docker compose logs -f # 5. 停止并清理 docker compose down ``` **目录:** [基本结构](#一基本结构) · [完整示例](#二完整示例) · [常用配置](#三常用配置详解) · [多环境](#四多环境配置) · [常用命令](#五常用命令) · [常见问题](#六常见问题) · [模板速查](#七常用模板速查) · [格式演进](#八compose-文件格式演进) · [高级配置](#九高级配置) · [最佳实践](#十最佳实践) · [速查卡](#十一快速参考卡) --- ## 一、基本结构 ```yaml # docker-compose.yml version: '3.8' services: web: # 前端/后端应用 db: # 数据库 redis: # 缓存 nginx: # 反向代理 networks: # 网络定义 volumes: # 数据卷定义 ``` --- ## 二、完整示例 ### 2.1 Node.js + MySQL + Redis 全栈项目 ```yaml 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 构建 ```yaml 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` — 启动顺序 ```yaml services: api: depends_on: db: condition: service_healthy # 等 db 健康检查通过 redis: condition: service_started # 等 redis 启动即可 ``` > **注意:** `depends_on` 只管**启动顺序**,不管**可用性**。`condition: service_healthy` + `healthcheck` 才能真正等服务就绪。 ### 3.3 `healthcheck` — 健康检查 ```yaml 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 || exit 1` | | Nginx | `curl -f http://localhost/ || exit 1` | | PostgreSQL | `pg_isready -h localhost` | ### 3.4 `environment` — 环境变量 ```yaml # 方式一:列表格式 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` — 数据持久化 ```yaml 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` — 重启策略 ```yaml restart: always # 永远重启(包括手动停止后重启) restart: on-failure # 仅失败时重启 restart: unless-stopped # 除非手动停止,否则重启(推荐) restart: no # 不自动重启(默认) ``` ### 3.7 `ports` vs `expose` ```yaml ports: - "8080:80" # 宿主端口:容器端口(外部可访问) - "127.0.0.1:8080:80" # 仅本地可访问 - "3000" # 随机端口 expose: - "3000" # 仅容器间通信,外部不可访问 ``` --- ## 四、多环境配置 ### 4.1 使用覆盖文件 ```yaml # docker-compose.yml(基础配置) services: api: build: . environment: - NODE_ENV=development volumes: - ./server:/app # 开发时热重载 db: image: mysql:8.0 ``` ```yaml # docker-compose.prod.yml(生产覆盖) services: api: environment: - NODE_ENV=production # 覆盖开发时的 volume 挂载 volumes: [] # 生产时不要挂载宿主机目录 ``` ```bash # 使用:基础 + 生产覆盖 docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d ``` ### 4.2 更简洁的方式(环境变量控制) ```yaml # docker-compose.yml services: api: build: . environment: - NODE_ENV=${NODE_ENV:-development} - DB_HOST=${DB_HOST:-db} volumes: - ${MOUNT_VOLUMES:-./server:/app} ``` ```bash # 开发环境(默认) docker compose up -d # 生产环境 NODE_ENV=production MOUNT_VOLUMES="" docker compose up -d ``` --- ## 五、常用命令 ```bash # 启动所有服务(后台) 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 容器间无法互相访问 ```yaml # 确保所有服务在同一网络下 services: api: networks: [app-network] db: networks: [app-network] networks: app-network: driver: bridge ``` > 默认情况下,Docker Compose 会为同一个 compose 文件创建同一个网络,不同 compose 文件的容器**不能互相访问**。 ### 6.2 数据库启动慢,应用连不上 ```yaml services: api: depends_on: db: condition: service_healthy # 健康检查通过才启动 ``` 或在应用代码中添加重试逻辑。 ### 6.3 端口冲突 ```bash # 查看端口占用 netstat -ano | findstr :3000 # Windows lsof -i :3000 # macOS/Linux ``` 修改 `docker-compose.yml` 中的端口映射: ```yaml ports: - "3001:3000" # 宿主机 3001 → 容器 3000 ``` ### 6.4 `.env` 文件 ```bash # 在项目根目录创建 .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) ```yaml services: web: build: . ports: - "80:80" restart: always ``` ### 7.2 Node.js + PostgreSQL ```yaml 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 全功能模板 ```yaml 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 格式: ```yaml # 新版写法(推荐) 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 如何判断使用哪种格式 ```bash # 查看 Compose 版本 docker compose version # Compose V2+(2020 年起)→ 使用 Compose Specification 格式 # 使用 `docker compose`(注意是空格,不是连字符) ``` > **建议:** 新项目直接使用无 version 的新格式,兼容性更好。 --- ## 九、高级配置 ### 9.1 `deploy` — 资源限制(适用于 Compose V3+) ```yaml 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` — 按需启停服务 ```yaml 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"] ``` ```bash # 启动 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` — 配置文件管理 ```yaml 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` — 敏感信息管理 ```yaml 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 其他实用配置 ```yaml 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 安全性 ```yaml # ✅ 使用非 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 可靠性 ```yaml # ✅ 所有外部依赖都加 healthcheck db: healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] start_period: 30s # ✅ 合理的重启策略 restart: unless-stopped # ✅ 依赖顺序用 condition depends_on: db: condition: service_healthy ``` ### 10.3 可维护性 ```yaml # ✅ 使用 .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 性能优化 ```yaml # ✅ 生产环境使用 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"` |