docker-compose编排实战
1. 概念
docker-compose 是定义和运行多容器应用的工具。一份 yaml 描述所有服务、网络、卷。前端最大用途是本地开发:一键起 Web + DB + Redis + Nginx。
新版 Docker 内置 docker compose(无连字符),老版命令 docker-compose 仍可用。
2. 基础结构
# compose.yaml (或 docker-compose.yml)
services:
web:
image: node:20-alpine
working_dir: /app
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
NODE_ENV: development
DATABASE_URL: postgres://app:app@db:5432/app
depends_on:
db:
condition: service_healthy
command: npm run dev
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
ports:
- "6379:6379"
volumes:
pgdata:
redisdata:
3. 命令速查
docker compose up # 启动(前台)
docker compose up -d # 后台
docker compose up --build # 强制 rebuild
docker compose down # 停止 + 删除容器和网络
docker compose down -v # 同时删除卷(彻底重置)
docker compose ps # 看状态
docker compose logs -f web # 看日志
docker compose exec web sh # 进容器
docker compose run --rm web npm test # 一次性命令
docker compose restart web # 重启某服务
docker compose pull # 拉新镜像
docker compose config # 解析后的配置(debug 用)
4. 服务间通信
compose 自动创建网络,服务名作为 DNS 名:
services:
web:
environment:
DATABASE_URL: postgres://db:5432/app # 用 db 这个服务名连
db:
image: postgres
容器内 ping/curl http://db:5432 就能通。不要用 localhost / 127.0.0.1 跨容器通信。
5. 环境变量
5.1 .env 文件自动加载
# .env
POSTGRES_PASSWORD=secret
NODE_VERSION=20
services:
db:
image: postgres:${POSTGRES_VERSION:-16} # 默认值
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
5.2 多环境 override
# 默认加载 compose.yaml + compose.override.yaml
docker compose up
# 显式指定多文件
docker compose -f compose.yaml -f compose.prod.yaml up
# compose.yaml(基线)
services:
web:
image: myapp
environment:
NODE_ENV: development
# compose.prod.yaml(生产覆盖)
services:
web:
environment:
NODE_ENV: production
restart: always
6. depends_on 与启动顺序
depends_on 只保证启动顺序,不保证服务"就绪"。db 启动后还要 5-10 秒才能接受连接。用 healthcheck + condition:
services:
web:
depends_on:
db:
condition: service_healthy
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
应用层也要做重试(连不上 DB 退避重连),不要纯靠 compose。
7. profiles(按需启动)
不是所有服务都常用:
services:
web:
image: myapp
db:
image: postgres
pgadmin:
image: dpage/pgadmin4
profiles: ["debug"] # 默认不启
mailhog:
image: mailhog/mailhog
profiles: ["debug"]
docker compose up # 不启 profile 的
docker compose --profile debug up # 包含 debug 服务
8. 资源限制
services:
web:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
memory: 512M
# 简写(不需要 swarm 模式)
cpus: 2
mem_limit: 2g
mem_reservation: 512m
9. 日志驱动
services:
web:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
不限制的话日志写满磁盘。
10. 完整前端开发栈例子
services:
web:
build:
context: .
target: development
volumes:
- .:/app
- node_modules:/app/node_modules
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:app@db:5432/app
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
command: npm run dev
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
nginx:
image: nginx:alpine
volumes:
- ./nginx.dev.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "8080:80"
depends_on:
- web
mailhog:
image: mailhog/mailhog
ports:
- "8025:8025"
profiles: ["debug"]
volumes:
pgdata:
redisdata:
node_modules:
11. 故障排查
# 看为什么起不来
docker compose logs <service>
docker compose ps # 看 unhealthy
docker compose config # yaml 语法 / 变量替换错误
# 进容器查
docker compose exec web sh
# 网络
docker compose exec web nslookup db
docker network inspect <project>_default
12. 常见反模式
depends_on不配 healthcheck:依赖服务起来但没就绪,应用启动失败- 跨容器用 localhost:永远连不上
volumes: ["./:/app"]把 node_modules 也挂出来:宿主机 node_modules 覆盖容器内的,platform 不兼容(macOS 上的不能给容器 linux 用)- 生产用 docker-compose:单机不容灾,应该上 K8s / Swarm
- 不限日志:磁盘塞满
- 共享 .env 含密码进 git:泄密。
.env必须 gitignore,提供.env.example - 服务名用驼峰:DNS 不支持,要小写 + 横线 / 下划线
13. 延伸阅读
- Compose 规范
- Docker Compose 官方文档
- Awesome Compose 示例 — 上百个真实示例