跳到主要内容

🎼 Docker Compose 编排

🤔 什么是 Docker Compose

Docker Compose 是一个多容器编排工具,通过一个 compose.yml(旧版为 docker-compose.yml)文件定义和运行多容器 Docker 应用。

核心价值:一条命令启动整个应用栈(Web + Database + Redis + ...)

传统方式 vs Compose 方式
# ❌ 传统方式:手动启动每个容器
docker run -d --name db -e POSTGRES_PASSWORD=secret postgres:16-alpine
docker run -d --name redis redis:7-alpine
docker run -d --name web --link db --link redis -p 3000:3000 myapp:latest

# ✅ Compose 方式:一条命令
docker compose up -d

📄 compose.yml 文件结构

compose.yml 基本结构
version: '3.9' # 可选,Compose v2 已不强制要求

services: # 定义容器服务
web:
build: .
ports:
- '3000:3000'

volumes: # 定义数据卷
db_data:

networks: # 定义网络
app_net:

顶级配置项

配置项说明必需
services定义容器服务(最核心)✅ 必需
volumes定义命名数据卷❌ 可选
networks定义自定义网络❌ 可选
configs定义配置文件(Swarm 模式)❌ 可选
secrets定义密钥(Swarm 模式)❌ 可选

🏗️ Services 配置详解

services 是 compose.yml 中最核心的部分,每个 service 对应一个容器。

web 服务完整配置示例
services:
web:
# 镜像来源
image: myapp:latest
build:
context: .
dockerfile: Dockerfile
args:
NODE_ENV: production

# 容器命名
container_name: myapp-web

# 重启策略
restart: unless-stopped

# 端口映射
ports:
- '3000:3000'
- '9229:9229' # Node.js 调试端口

# 环境变量
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
env_file:
- .env

# 卷挂载
volumes:
- ./data:/app/data:ro
- app_logs:/app/logs

# 网络
networks:
- app_net

# 依赖关系
depends_on:
db:
condition: service_healthy
redis:
condition: service_started

# 健康检查
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

# 资源限制(Compose v2)
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M

常用 Services 配置项速查

配置项说明示例
image使用的镜像image: postgres:16-alpine
build构建配置build: .build: { context: ., dockerfile: Dockerfile }
ports端口映射ports: ["3000:3000", "9229:9229"]
environment环境变量environment: ["NODE_ENV=production"]
env_file环境变量文件env_file: [.env, .env.prod]
volumes卷挂载volumes: ["./data:/app/data"]
networks加入的网络networks: ["app_net"]
depends_on依赖服务depends_on: [db, redis]
restart重启策略restart: unless-stopped
healthcheck健康检查见上例
command覆盖默认命令command: npm run dev
entrypoint覆盖默认入口点entrypoint: ["/entrypoint.sh"]

🌟 真实案例:Web + PostgreSQL + Redis

以下是一个典型的全栈应用 Compose 配置:

compose.yml — 完整生产级配置
services:
# ─── Web 应用 ────────────────────────────────
web:
build:
context: .
dockerfile: Dockerfile
container_name: myapp-web
restart: unless-stopped
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
- REDIS_URL=redis://redis:6379
env_file:
- .env.production
volumes:
- ./uploads:/app/uploads:ro
networks:
- app_net
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

# ─── PostgreSQL 数据库 ────────────────────────
db:
image: postgres:16-alpine
container_name: myapp-db
restart: unless-stopped
ports:
- '5432:5432'
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- db_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app_net
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5

# ─── Redis 缓存 ──────────────────────────────
redis:
image: redis:7-alpine
container_name: myapp-redis
restart: unless-stopped
ports:
- '6379:6379'
command: redis-server --appendonly yes --requirepass secret
volumes:
- redis_data:/data
networks:
- app_net
healthcheck:
test: ['CMD', 'redis-cli', '-a', 'secret', 'ping']
interval: 10s
timeout: 5s
retries: 5

# ─── Nginx 反向代理 ──────────────────────────
nginx:
image: nginx:alpine
container_name: myapp-nginx
restart: unless-stopped
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
networks:
- app_net
depends_on:
- web

networks:
app_net:
driver: bridge

volumes:
db_data:
redis_data:

配套 .env 文件

# 数据库配置
POSTGRES_USER=postgres
POSTGRES_PASSWORD=mysecretpassword
POSTGRES_DB=myapp

# Redis 配置
REDIS_PASSWORD=mysecretpassword

# 应用配置
NODE_ENV=production
PORT=3000

:::tip 关于 .env 文件

  • Compose 会自动加载同级目录的 .env 文件
  • 变量使用 ${VARIABLE}$VARIABLE 引用
  • 敏感信息应使用 secrets 或运行时挂载,不应提交到 Git

:::

🔧 Docker Compose 常用命令

docker compose up — 启动服务

# 启动所有服务(前台运行,Ctrl+C 停止)
docker compose up

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

# 重新构建后启动(代码变更后)
docker compose up -d --build

# 启动指定服务
docker compose up -d web

# 强制重新创建容器(即使配置未变)
docker compose up -d --force-recreate

docker compose down — 停止并删除

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

# 同时删除命名卷
docker compose down -v

# 同时删除镜像(删除所有服务使用的镜像)
docker compose down --rmi all

# 停止但不删除 volumes
docker compose down --volumes # 删除 volumes

docker compose logs — 查看日志

# 查看所有服务日志
docker compose logs

# 实时跟踪日志(类似 tail -f)
docker compose logs -f

# 查看指定服务日志
docker compose logs web

# 显示最后 100 行
docker compose logs --tail=100 web

# 带时间戳
docker compose logs -t web

docker compose ps — 查看服务状态

# 查看运行中的服务
docker compose ps

# 查看所有服务(含已停止)
docker compose ps -a

docker compose exec — 进入容器

# 在运行中的容器中执行命令
docker compose exec web bash

# 以 root 用户进入
docker compose exec -u root web bash

# 执行单条命令
docker compose exec web npm run db:migrate

docker compose build — 构建镜像

# 构建所有服务镜像
docker compose build

# 构建指定服务
docker compose build web

# 不使用缓存重新构建
docker compose build --no-cache

# 并行构建(加速)
docker compose build --parallel

docker compose restart — 重启服务

# 重启所有服务
docker compose restart

# 重启指定服务
docker compose restart web

命令速查表

命令作用常用参数
docker compose up -d后台启动所有服务--build 重新构建
docker compose down停止并删除容器网络-v 删除卷,--rmi all 删除镜像
docker compose ps查看服务状态-a 显示已停止
docker compose logs -f实时查看日志--tail=100 最后100行
docker compose exec web sh进入容器-u root 以 root 进入
docker compose build构建镜像--no-cache 无缓存
docker compose restart web重启服务
docker compose stop停止服务(不删除)
docker compose start启动已停止的服务
docker compose pull拉取最新镜像--ignore-pull-failures
docker compose config验证并显示配置--services 显示服务名
docker compose top显示运行进程

🔐 环境变量与 .env 文件

Compose 支持多种方式管理环境变量:

1. 直接在 compose.yml 中定义

services:
web:
environment:
- NODE_ENV=production
- API_KEY=secret-key

2. 使用 .env 文件(推荐)

compose.yml
services:
web:
image: myapp:latest
environment:
- NODE_ENV=${NODE_ENV:-production}
- API_PORT=${API_PORT:-3000}
NODE_ENV=production
API_PORT=3000
DATABASE_URL=postgresql://postgres:secret@localhost:5432/myapp

3. 使用 env_file 指定文件

services:
web:
env_file:
- .env.production
- .env.secrets

:::warning .env 文件安全注意事项

  • 不要提交 .env 到 Git:在 .gitignore 中添加 .env*
  • 提供 .env.example:列出所需变量但不填写真实值
  • 生产环境:使用 CI/CD 注入或密钥管理服务

:::

# .env.example — 复制为 .env 并填入真实值
NODE_ENV=development
API_PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-jwt-secret-here

⚖️ Docker Compose vs Kubernetes:如何选择

维度Docker ComposeKubernetes
复杂度简单,YAML 直观复杂,学习曲线陡峭
适用场景本地开发、小型部署生产环境、大规模集群
健康检查支持(healthcheck)支持(liveness/readiness)
自动扩缩容❌ 不支持✅ 支持(HPA)
滚动更新❌ 不支持✅ 支持
服务发现Docker DNSCoreDNS + Service
存储本地卷、绑定挂载PV/PVC、CSI
网络Docker 网络CNI 插件(Calico/Flannel)
资源限制支持(v2)完善(CPU/Memory/Storage)
监控需外接内置 Metrics Server

决策树

我需要编排多容器应用
├── 本地开发 / CI 测试
│ └── ✅ 使用 Docker Compose
├── 小型生产部署(< 5 节点)
│ ├── 团队无 K8s 经验 → ✅ Docker Compose + 手动管理
│ └── 团队有 K8s 经验 → ⚠️ 可考虑 K8s
└── 中大型生产部署(≥ 5 节点)/ 高可用需求
└── ✅ 使用 Kubernetes

:::tip 混合使用策略

许多团队采用混合策略

  • 开发环境:Docker Compose(快速、简单)
  • 生产环境:Kubernetes(可扩展、高可用)

可以使用 kompose 工具将 Compose 文件转换为 K8s 配置:

kompose convert -f compose.yml -o k8s/

:::

🚀 Compose 高级特性

Profile — 环境配置

compose.yml with profiles
services:
web:
image: myapp:latest
profiles:
- web

db:
image: postgres:16-alpine
profiles:
- db

redis:
image: redis:7-alpine
profiles:
- cache

# 仅开发环境启用的服务
adminer:
image: adminer:latest
ports:
- '8080:8080'
profiles:
- dev
使用 profile 启动
# 默认启动(所有服务)
docker compose up -d

# 仅启动 web 和 db profile 的服务
docker compose --profile web --profile db up -d

# 启动 dev profile(包含 adminer)
docker compose --profile dev up -d

extends — 配置复用

compose.base.yml — 基础配置
services:
app:
image: myapp:latest
environment:
- NODE_ENV=production
restart: unless-stopped
compose.yml — 继承基础配置
services:
web:
extends:
file: compose.base.yml
service: app
ports:
- '3000:3000'
depends_on:
- db

worker:
extends:
file: compose.base.yml
service: app
command: npm run worker

📋 Compose 最佳实践

1. 使用命名卷而非绑定挂载(生产环境)

❌ 开发环境可用,生产不推荐
volumes:
- ./data:/app/data # 绑定挂载:依赖宿主机路径
✅ 生产推荐:命名卷
volumes:
db_data: # 命名卷:Docker 管理,可迁移

services:
db:
volumes:
- db_data:/var/lib/postgresql/data

2. 设置重启策略

重启策略选择
services:
web:
# always:始终重启(包括手动停止后 daemon 重启)
restart: always

worker:
# unless-stopped:除非手动停止,否则始终重启(推荐)
restart: unless-stopped

batch:
# no:不重启(批量任务)
restart: 'no'

debug:
# on-failure:失败时重启
restart: on-failure:5 # 最多重启 5 次

3. 使用 healthcheck 控制启动顺序

使用 healthcheck 而非 wait-for-it 脚本
services:
db:
image: postgres:16-alpine
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5

web:
image: myapp:latest
depends_on:
db:
condition: service_healthy # 等待 db 健康后才启动

4. 资源限制

Compose v2 资源限制
services:
web:
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M

🔗 下一步