Docker: Docker Compose入门
最后更新:2026-08-26
5 条 docker run 命令变成 1 条 docker compose up——Compose 让多容器部署从手动操作变成声明式配置。
1. 你将学到
- docker-compose.yml 结构与语法
- 服务定义与依赖控制
- 卷与网络的声明式管理
- 环境变量管理策略
- docker compose 常用命令
2. 一个开发者的真实故事
(1) 痛点:每次调试 5 条 docker run
Alice 每次调试都要手动敲 5 条 docker run 命令启动 Web/DB/Cache/Queue/Worker 四个容器——参数多、顺序不能错、环境变量容易打错。有一次她忘了加 --network app-net,花了 1 小时排查为什么 Web 连不上数据库。
(2) Docker Compose 声明式配置的解法
Bob 写了一个 docker-compose.yml,Alice 从此只需 docker compose up -d。
YAML
# docker-compose.yml - One file defines everything
services:
web:
image: nginx:alpine
ports: ["8080:80"]
depends_on:
- api
api:
build: .
environment:
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
db:
image: postgres:15-alpine
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
volumes:
- pg-data:/var/lib/postgresql/data
volumes:
pg-data:
networks:
default:
name: app-net
(3) 收益:5 条命令→1 条命令
部署从 5 条命令 + 手动配置降到 1 条 docker compose up -d。新人 5 分钟就能跑起整个项目。
3. docker-compose.yml 结构
(1) 三大顶级字段
YAML
# docker-compose.yml structure
services: # Container definitions (required)
web:
image: nginx:alpine
volumes: # Named volume declarations (optional)
pg-data:
networks: # Custom network declarations (optional)
app-net:
(2) docker run vs docker compose 对比
| 维度 | docker run | docker compose |
|---|---|---|
| 定义方式 | 命令行参数 | YAML 文件 |
| 可复现性 | 低(依赖操作者记忆) | 高(文件可提交 Git) |
| 多容器 | 多条命令 | 一个文件 |
| 网络/卷 | 手动创建 | 自动声明式管理 |
| 环境变量 | 多个 -e 参数 | env_file 或 environment 块 |
| 版本控制 | ❌ | ✅ YAML 可 git diff |
4. Services 配置详解
(1) 常用服务字段
| 字段 | 作用 | 示例 |
|---|---|---|
image |
使用已有镜像 | image: nginx:alpine |
build |
从 Dockerfile 构建 | build: . 或 build: { context: ., dockerfile: Dockerfile.prod } |
ports |
端口映射 | ports: ["8080:80"] |
environment |
环境变量 | environment: { POSTGRES_PASSWORD: secret } |
env_file |
从文件加载变量 | env_file: .env |
volumes |
卷挂载 | volumes: [pg-data:/var/lib/postgresql/data] |
depends_on |
启动依赖 | depends_on: [db] |
restart |
重启策略 | restart: unless-stopped |
networks |
指定网络 | networks: [app-net] |
healthcheck |
健康检查 | healthcheck: { test: ["CMD", "curl", "-f", "http://localhost/"] } |
▶ 示例:编写最简 compose 文件(难度⭐)
YAML
# Minimal docker-compose.yml
services:
web:
image: nginx:alpine
ports:
- "8080:80"
BASH
# Start with compose
docker compose up -d
# Verify
docker compose ps
5. 依赖控制:depends_on
(1) 三种等待策略
| 策略 | 语法 | 等待到 | 说明 |
|---|---|---|---|
| started(默认) | depends_on: [db] |
容器启动 | 不保证服务就绪 |
| healthy | depends_on: { db: { condition: service_healthy } } |
健康检查通过 | ✅ 推荐生产使用 |
| completed | depends_on: { init: { condition: service_completed_successfully } } |
容器成功退出 | 初始化任务 |
▶ 示例:depends_on + healthcheck 依赖控制(难度⭐⭐)
YAML
services:
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
api:
build: .
environment:
DATABASE_URL: postgresql://postgres:secret@db:5432/myapp
depends_on:
db:
condition: service_healthy
volumes:
pg-data:
💡 提示:
depends_on: [db](默认)只等 db 容器启动,不等 PostgreSQL 就绪。API 可能在 DB 未准备好时就尝试连接而失败。condition: service_healthy 确保 PostgreSQL 真正就绪后 API 才启动。
6. Volumes 和 Networks 声明
▶ 示例:声明卷和网络(难度⭐⭐)
YAML
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./src:/usr/share/nginx/html:ro # Bind mount (read-only)
- nginx-cache:/var/cache/nginx # Named volume
networks:
- frontend
- backend
api:
build: .
networks:
- backend
- database
db:
image: postgres:15-alpine
volumes:
- pg-data:/var/lib/postgresql/data
networks:
- database
volumes:
pg-data:
nginx-cache:
networks:
frontend:
backend:
database:
internal: true # No external access
7. 环境变量管理
(1) 三种方式对比
| 方式 | 语法 | 适用场景 |
|---|---|---|
| environment 块 | environment: { KEY: VALUE } |
少量固定变量 |
| env_file | env_file: .env |
多变量/敏感信息 |
| shell 变量 | environment: { KEY: ${VAR} } |
动态配置 |
▶ 示例:env_file 和变量替换(难度⭐⭐)
YAML
# docker-compose.yml with variable substitution
services:
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD:-defaultsecret}
POSTGRES_DB: ${DB_NAME:-myapp}
env_file:
- .env.db
api:
build: .
environment:
DATABASE_URL: postgresql://postgres:${DB_PASSWORD:-defaultsecret}@db:5432/${DB_NAME:-myapp}
BASH
# .env.db
POSTGRES_USER=appuser
POSTGRES_PASSWORD=secret123
📌 重点:
${VAR:-default} 语法:如果 VAR 未设置,使用 default 值。这样 compose 文件有默认值,生产环境用 .env 文件覆盖。
8. Docker Compose 常用命令
| 命令 | 作用 | 示例 |
|---|---|---|
docker compose up -d |
启动所有服务(后台) | docker compose up -d |
docker compose down |
停止并删除所有容器/网络 | docker compose down |
docker compose down -v |
同时删除卷 | docker compose down -v |
docker compose ps |
查看服务状态 | docker compose ps |
docker compose logs |
查看日志 | docker compose logs -f api |
docker compose exec |
进入容器 | docker compose exec api bash |
docker compose build |
重新构建镜像 | docker compose build api |
docker compose pull |
拉取最新镜像 | docker compose pull |
docker compose config |
验证并显示合并后的配置 | docker compose config |
▶ 示例:docker compose up -d 启动(难度⭐)
BASH
# Start all services in detached mode
docker compose up -d
# Follow logs from all services
docker compose logs -f
# Follow logs from a specific service
docker compose logs -f api
▶ 示例:docker compose exec 进入容器(难度⭐)
BASH
# Open shell in the api service container
docker compose exec api bash
# Run a one-off command
docker compose exec db psql -U postgres -d myapp
▶ 示例:docker compose down 清理(难度⭐)
BASH
# Stop and remove containers + networks
docker compose down
# Also remove named volumes (WARNING: deletes data)
docker compose down -v
# Also remove images
docker compose down --rmi all
9. 完整示例:WordPress + MySQL
YAML
# ============================================
# docker-compose.yml: WordPress + MySQL
# Features: volumes, networks, depends_on, healthcheck
# ============================================
services:
wordpress:
image: wordpress:6.4-php8.2-apache
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-wppass123}
WORDPRESS_DB_NAME: wordpress
volumes:
- wp-content:/var/www/html/wp-content
depends_on:
mysql:
condition: service_healthy
restart: unless-stopped
networks:
- wp-net
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootsecret}
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: ${DB_PASSWORD:-wppass123}
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- wp-net
volumes:
mysql-data:
wp-content:
networks:
wp-net:
BASH
# Deploy
docker compose up -d
# Verify
docker compose ps
docker compose logs -f wordpress
# Access WordPress
# Open http://localhost:8080 in browser
# Clean up (keeps data)
docker compose down
# Clean up everything (deletes data)
docker compose down -v
❓ 常见问题
Q docker-compose.yml 用哪个版本?
A 新版 Docker Compose V2 不再需要 version 字段。直接从 services: 开始写即可。如果看到旧教程写
version: "3.8",可以删掉——V2 忽略它。Q depends_on 能保证服务就绪吗?
A 默认
depends_on: [db] 只保证 db 容器启动,不保证 PostgreSQL 就绪。加 condition: service_healthy 才等健康检查通过。这是 Compose 新手最常见的坑——服务启动但依赖未就绪导致连接失败。Q Compose 文件里的环境变量怎么管理?
A 三层管理:① docker-compose.yml 里的 environment 块(非敏感默认值);②
.env 文件(环境特定值,不提交 Git);③ ${VAR:-default} 语法(给默认值兜底)。敏感密码不要写在 YAML 里,用 .env 文件 + .gitignore。Q docker compose down 会删数据卷吗?
A 默认不删除。
docker compose down 只删除容器和网络,Named Volume 保留。加 -v 才删除卷。生产环境不要用 down -v,只用 down。Q Compose 项目名有什么用?
A 项目名隔离不同 Compose 应用的资源。默认用当前目录名。
docker compose -p myproject up 自定义项目名。同一台机器可以运行多个 Compose 项目,互不干扰。📖 小节
- docker-compose.yml 用声明式 YAML 替代多条 docker run 命令
- 三大顶级字段:services(容器定义)、volumes(持久化卷)、networks(网络)
depends_on+condition: service_healthy确保依赖真正就绪- 环境变量:environment 块 + env_file + ${VAR:-default} 三层管理
docker compose up -d一键启动,docker compose down一键清理docker compose config验证配置文件语法,避免运行时才发现错误
📝 作业
- 基础题(难度⭐):为 Phase 1 的 LEMP 栈(Nginx+PHP+MySQL)编写 docker-compose.yml,用
docker compose up -d启动。 - 进阶题(难度⭐⭐):在 compose 文件中添加 depends_on + healthcheck,确保 MySQL 就绪后 PHP-FPM 才启动。
- 挑战题(难度⭐⭐⭐):用
docker compose logs排查一个启动失败的服务,分析日志找到根因并修复。