18 KiB
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" |