docker Compose 实战
多容器编排的标配工具。学会 docker Compose,才算真正会用 docker 做开发。
一、为什么需要 docker Compose?
真实项目很少只有一个容器。一个典型 Web 应用至少需要:
Web 容器(nginx) ←→ 反向代理
App 容器(Flask/Spring Boot) ←→ 业务逻辑
DB 容器(MySQL/PostgreSQL) ←→ 数据存储
Redis 容器 ←→ 缓存
手动 docker run 启动每个容器? 太痛苦了。
docker Compose 让你用一个 YAML 文件定义和管理整个应用栈。
二、核心概念
2.1 什么是 docker Compose?
docker Compose 是 docker 官方的多容器编排工具,通过一个 docker-compose.yml 文件定义服务,一键启动/停止/重建。
适用场景:开发环境、测试环境、单机部署。 生产多机编排 → 用 Kubernetes(后续会学)。
2.2 核心组件
| 概念 | 说明 |
|---|---|
| Service(服务) | 一个容器,比如 nginx、mysql、redis |
| Image | 镜像名称 |
| Build | 本地构建上下文(路径或 git 仓库) |
| Ports | 端口映射 HOST:CONTAINER |
| Volumes | 数据卷挂载 |
| Environment | 环境变量 |
| Networks | 自定义网络 |
| Depends_on | 启动顺序依赖 |
三、docker-compose.yml 完整示例
version: "3.8"
services:
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
networks:
- app-net
restart: unless-stopped
app:
build: ./app
ports:
- "8080:8080"
environment:
- DB_HOST=mysql
- DB_PASS=secret123
- REDIS_HOST=redis
volumes:
- ./app:/app
- app-data:/app/data
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- app-net
restart: unless-stopped
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_DATABASE=myapp
- MYSQL_USER=appuser
- MYSQL_PASSWORD=apppass
volumes:
- mysql-data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 5
networks:
- app-net
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- app-net
command: redis-server --appendonly yes
networks:
app-net:
volumes:
mysql-data:
redis-data:
app-data:
四、常用命令
4.1 基本操作
# 一键启动所有服务(后台)
docker compose up -d
# 一键停止所有服务
docker compose stop
# 停止并删除容器(数据卷保留)
docker compose down
# 停止并删除容器 + 数据卷(慎用!)
docker compose down -v
# 查看服务状态
docker compose ps
# 查看日志(所有服务)
docker compose logs
# 查看指定服务日志(实时跟踪)
docker compose logs -f app
# 重建并启动(修改 Dockerfile 或配置后)
docker compose up -d --build
# 拉取最新镜像
docker compose pull
4.2 单容器操作
# 执行一条命令(相当于 docker exec)
docker compose exec app python manage.py migrate
# 进入容器 shell
docker compose exec app bash
# 临时启动一个新服务
docker compose run --rm app python script.py
五、关键配置详解
5.1 depends_on
depends_on:
- mysql # 只等容器创建,不等服务就绪
- redis:
condition: service_started # 等容器启动完成
- mysql:
condition: service_healthy # 等健康检查通过
⚠️
depends_on只控制启动顺序,不控制服务是否真正可用(如 DB 初始化完成)。
5.2 healthcheck
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s # 每 10 秒检查一次
timeout: 3s # 超时时间
retries: 3 # 连续失败 3 次标记不健康
start_period: 30s # 启动后 30 秒内失败不计入
5.3 environment vs env_file
# 方式一:直接写(适合少量变量)
environment:
- DB_HOST=mysql
- DEBUG=false
# 方式二:从文件读取(推荐,安全)
env_file:
- .env # 所有变量
- .env.prod # 覆盖生产变量
5.4 volumes 命名规则
# 匿名卷(docker 自动命名,不推荐)
volumes:
- /app/data
# 具名卷(推荐,可跨服务共享、可备份)
volumes:
- mysql-data:/var/lib/mysql
# 绑定挂载(代码热更新,开发场景)
volumes:
- ./app:/app
5.5 restart 策略
| 值 | 说明 |
|---|---|
no |
不重启(默认) |
on-failure |
非 0 退出码时重启 |
always |
总是重启(包括 docker 重启) |
unless-stopped |
除非手动 stop,否则总是重启(推荐) |
六、多环境配置
6.1 基础文件 + 覆盖文件
# docker-compose.yml(基础)
services:
app:
build: ./app
ports:
- "8080:8080"
# docker-compose.override.yml(开发环境,自动合并)
services:
app:
ports:
- "8080:8080"
volumes:
- ./app:/app
environment:
- DEBUG=true
# docker-compose.prod.yml(生产覆盖)
services:
app:
ports:
- "80:80"
restart: always
deploy:
replicas: 3
# 开发环境(默认合并 override)
docker compose up
# 生产环境(显式指定)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
6.2 环境变量控制
# 用 .env 文件控制
ENV=prod docker compose up
# 命令行覆盖
docker compose up -e DB_HOST=prod-mysql
七、docker Compose vs K8s
| 维度 | docker Compose | Kubernetes |
|---|---|---|
| 适用范围 | 单机 | 多机集群 |
| 容器数量 | 几十个以内 | 数千个 |
| 自愈能力 | 无 | ✅ 自动重启/调度 |
| 滚动更新 | ❌ | ✅ |
| 自动扩缩容 | ❌ | ✅ |
| 服务发现 | ✅(内置 DNS) | ✅(内置 DNS) |
| 学习曲线 | 低 | 高 |
| 适用阶段 | 开发→单机生产 | 大规模集群 |
🎯 学习路径:先精通 docker Compose,再进军 Kubernetes。
八、常见面试题
- docker Compose 的
depends_on能保证依赖服务可用吗? -
不能。
depends_on只保证容器启动顺序,不保证服务真正可用(如 DB 初始化完成)。必须配合healthcheck+ 应用层重试。 -
docker compose down和docker compose down -v的区别? -
不加
-v:删除容器但保留数据卷;加-v:连数据卷一起删除,数据全部丢失。 -
如何用 docker Compose 做开发热更新?
-
用绑定挂载
volumes: ["./app:/app"],代码修改后容器内实时生效(配合容器内自动重载工具)。 -
restart: unless-stopped和restart: always的区别? always:docker 守护进程启动时也重启;unless-stopped:手动 stop 后不再自动重启,更安全。