跳到主要内容

Docker Compose 编排

概述

Docker Compose 用于定义和管理多容器应用。通过一个 docker-compose.yml(或 compose.yml)文件描述所有服务、网络和卷,一条命令启动整个应用栈。

Compose V2

Docker Compose V2 已集成到 Docker CLI 中,使用 docker compose(无连字符)代替旧的 docker-compose。推荐使用 V2。

compose.yml 基础结构

compose.yml
# Compose 文件版本(V2 已不需要 version 字段)
services:
# ===== Web 应用 =====
web:
build:
context: .
dockerfile: Dockerfile
image: myapp:latest
container_name: myapp-web
ports:
- "8080:3000" # 主机端口:容器端口
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/mydb
env_file:
- .env # 从文件加载环境变量
depends_on:
db:
condition: service_healthy # 等待数据库健康
redis:
condition: service_started
volumes:
- ./uploads:/app/uploads # 绑定挂载
networks:
- app-network
restart: unless-stopped
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s

# ===== 数据库 =====
db:
image: postgres:16-alpine
container_name: myapp-db
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db-data:/var/lib/postgresql/data # 命名卷持久化
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化脚本
ports:
- "5432:5432"
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 10s
timeout: 5s
retries: 5

# ===== 缓存 =====
redis:
image: redis:7-alpine
container_name: myapp-redis
command: redis-server --appendonly yes --requirepass myredispass
volumes:
- redis-data:/data
ports:
- "6379:6379"
networks:
- app-network
restart: unless-stopped

# ===== 反向代理 =====
nginx:
image: nginx:1.25-alpine
container_name: myapp-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
- web
networks:
- app-network
restart: unless-stopped

# ===== 命名卷 =====
volumes:
db-data:
driver: local
redis-data:
driver: local

# ===== 自定义网络 =====
networks:
app-network:
driver: bridge

常用命令

# ===== 生命周期 =====
docker compose up -d # 后台启动所有服务
docker compose up -d --build # 重新构建并启动
docker compose up -d web # 只启动指定服务
docker compose down # 停止并删除容器/网络
docker compose down -v # 同时删除卷(慎用)
docker compose restart web # 重启指定服务

# ===== 状态查看 =====
docker compose ps # 查看服务状态
docker compose logs -f web # 实时查看日志
docker compose logs --tail=100 # 最后 100 行
docker compose top # 查看进程

# ===== 执行命令 =====
docker compose exec web sh # 进入运行中的容器
docker compose run --rm web sh # 创建临时容器执行

# ===== 构建与拉取 =====
docker compose build # 构建所有服务镜像
docker compose build --no-cache # 无缓存构建
docker compose pull # 拉取最新镜像

# ===== 扩缩容 =====
docker compose up -d --scale web=3 # 水平扩展到 3 个实例

环境变量管理

compose.yml
services:
web:
image: myapp
# 方式 1:直接定义
environment:
- NODE_ENV=production
- API_KEY=${API_KEY} # 引用宿主机环境变量
# 方式 2:文件加载
env_file:
- .env
- .env.local # 后加载的覆盖前面的
.env
# Compose 自动加载项目根目录的 .env
POSTGRES_USER=admin
POSTGRES_PASSWORD=secret123
APP_PORT=8080
.env 安全

.env 文件不要提交到 Git。在 .gitignore 中添加 .env,提供 .env.example 作为模板。

depends_on 与启动顺序

compose.yml
services:
web:
depends_on:
db:
condition: service_healthy # 等待 db 健康检查通过
redis:
condition: service_started # 等待 redis 容器启动
migration:
condition: service_completed_successfully # 等待迁移完成

migration:
build: .
command: npx prisma migrate deploy
depends_on:
db:
condition: service_healthy

Profiles 条件启动

compose.yml
services:
web:
image: myapp
# 无 profiles,默认启动

debug:
image: myapp-debug
profiles: ["debug"] # 只在 debug profile 激活时启动

monitoring:
image: prometheus
profiles: ["monitoring"]

grafana:
image: grafana/grafana
profiles: ["monitoring"]
# 默认只启动无 profile 的服务
docker compose up -d

# 启动包含 monitoring profile 的服务
docker compose --profile monitoring up -d

多环境配置

# 开发环境
docker compose -f compose.yml -f compose.dev.yml up -d

# 生产环境
docker compose -f compose.yml -f compose.prod.yml up -d
compose.yml - 基础配置
services:
web:
image: myapp
networks:
- app-network
compose.dev.yml - 开发覆盖
services:
web:
build: .
volumes:
- .:/app # 源码热重载
ports:
- "3000:3000"
environment:
- NODE_ENV=development
compose.prod.yml - 生产覆盖
services:
web:
image: registry.example.com/myapp:latest
deploy:
replicas: 3
resources:
limits:
cpus: "2.0"
memory: 1G
environment:
- NODE_ENV=production

实用配置示例

ELK 日志栈

compose.elk.yml
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
volumes:
- es-data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"]
interval: 10s
retries: 5

logstash:
image: docker.elastic.co/logstash/logstash:8.12.0
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline:ro
depends_on:
elasticsearch:
condition: service_healthy

kibana:
image: docker.elastic.co/kibana/kibana:8.12.0
ports:
- "5601:5601"
environment:
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
depends_on:
elasticsearch:
condition: service_healthy

volumes:
es-data:

Prometheus + Grafana 监控

compose.monitoring.yml
services:
prometheus:
image: prom/prometheus:v2.49.0
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
ports:
- "9090:9090"
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'

grafana:
image: grafana/grafana:10.3.0
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning:ro
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
depends_on:
- prometheus

volumes:
prometheus-data:
grafana-data:

常见面试问题

Q1: docker compose up 和 docker compose run 的区别?

答案

  • docker compose up:启动 compose 文件定义的所有(或指定)服务,创建网络和卷,适合启动整个应用
  • docker compose run:创建一个临时容器运行一次性命令(如数据库迁移、测试),默认不映射端口,加 --rm 可在运行后自动删除

Q2: 如何保证容器的正确启动顺序?

答案

depends_on 配合 condition:

  • service_started:等容器启动
  • service_healthy:等健康检查通过(推荐)
  • service_completed_successfully:等容器成功退出(适合初始化任务)

仅用 depends_on 不加 condition 只保证启动顺序,不保证服务就绪。

Q3: Compose 中如何管理敏感数据?

答案

  1. 环境变量文件.env 文件不提交 Git
  2. Docker Secrets(Swarm 模式):docker secret create
  3. 外部密钥管理:HashiCorp Vault 等
  4. 开发环境用 .env,生产环境通过 CI/CD 注入环境变量
安全注意

绝对不要在 compose.yml 或 Dockerfile 中硬编码密码。

相关链接