跳到主要内容

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. 延伸阅读