一个 docker run 解决不了的事
单容器用 docker run 还行,但真实项目至少要「数据库 + 缓存 + 后端 + 前端」四件套。用一堆 docker run 命令手动串联,网络、卷、启动顺序全是坑。Docker Compose 用一个 YAML 把这些定义成可版本化的声明,一条 docker compose up 全部拉起。
一、最小可用:MySQL + Redis + 后端
# docker-compose.yml
version: "3.9"
services:
mysql:
image: mysql:8.0
container_name: app-mysql
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: appdb
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
redis:
image: redis:7-alpine
container_name: app-redis
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
backend:
build: ./backend
container_name: app-backend
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/appdb
SPRING_REDIS_HOST: redis
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
volumes:
mysql-data:
二、三个关键点
1. 自定义网络与 Service 名即主机名
Compose 默认创建桥接网络,服务间用服务名互相访问(如 mysql、redis),不用管 IP。上例中后端连 jdbc:mysql://mysql:3306 即可。
2. 数据持久化用命名卷
容器删了数据就没,必须挂 volumes。命名卷(如 mysql-data)由 Docker 管理,比绑宿主机路径更干净、跨平台一致。
3. 启动顺序用 healthcheck + depends_on
后端不能比数据库先跑。depends_on: condition: service_healthy 配合各服务的 healthcheck,保证「库活了后端才起」,避免启动竞态。
三、常用命令
docker compose up -d # 后台启动全部
docker compose ps # 看状态
docker compose logs -f backend # 看某服务日志
docker compose down # 停止并删容器(卷保留)
docker compose down -v # 连卷一起删(慎用,清数据)
docker compose build # 重新构建含 Dockerfile 的服务
四、进阶:多环境与环境变量
把密码、端口抽成 .env 文件,Compose 自动读取:
# .env
MYSQL_ROOT_PASSWORD=strongpass
MYSQL_DATABASE=appdb
# compose 中引用
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
不同环境用 docker-compose.override.yml 或 -f 指定多文件叠加,生产/本地配置分离。
五、踩坑提醒
- 版本号别乱写:
version字段在新版 Compose 已可省略,写错反而报错。 - 端口冲突:宿主机端口被占会起不来,先
lsof -i:3306排查。 - 构建上下文:
build: ./backend需该目录有 Dockerfile。 - 开发用 bind mount 热更新:代码目录挂
./src:/app/src改代码即时生效。
小结
Docker Compose 把「多服务编排」从一堆易错的 shell 命令,变成一份可提交、可复现的 YAML。记住服务名即主机名、命名卷做持久化、healthcheck 管启动顺序三点,本地开发环境和 CI 测试环境就能做到「一条命令拉起、人人一致」。




