跳到主要内容

Docker Compose

Docker Compose 是用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 配置文件,可以配置应用的服务、网络和数据卷。

什么是 Docker Compose?

Docker Compose 让你能够:

  • 使用 YAML 文件定义多个服务
  • 一键启动和停止整个应用栈
  • 管理服务之间的依赖关系
  • 轻松地在不同环境间复制配置

典型应用场景

  • 开发环境:快速搭建完整的开发栈
  • 自动化测试:定义测试所需的服务
  • CI/CD 流水线:标准化构建和部署流程
  • 单主机部署:中小型应用的部署

安装

Docker Desktop 已内置 Docker Compose,无需额外安装。

Linux 单独安装

# 下载最新版本
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 验证安装
docker-compose --version

compose.yaml 文件结构

基本结构

# compose.yaml 或 docker-compose.yml

version: "3.8" # 可选,现代版本可省略

services:
# 定义服务
web:
image: nginx:latest
ports:
- "8080:80"

db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: example

networks:
# 定义网络
app-network:
driver: bridge

volumes:
# 定义数据卷
db-data:

版本说明

  • version 字段在现代 Docker Compose 中是可选的
  • 不同版本支持的功能略有不同
  • 推荐使用最新版本或省略 version 字段

服务配置

基本配置

services:
web:
# 使用镜像
image: nginx:latest

# 或者使用构建
build: .

# 或者指定 Dockerfile 路径
build:
context: ./app
dockerfile: Dockerfile.dev

# 容器名称
container_name: my-web

# 主机名
hostname: web-server

# 重启策略
restart: always

端口映射

services:
web:
# 单个端口
ports:
- "8080:80"

# 多个端口
ports:
- "8080:80"
- "8443:443"

# 指定协议
ports:
- "53:53/udp"

# 仅暴露给其他服务(不映射到主机)
expose:
- "3000"

环境变量

services:
db:
# 直接设置
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: myapp

# 从文件读取
env_file:
- .env
- .env.local

# 列表格式
environment:
- MYSQL_ROOT_PASSWORD=root123
- MYSQL_DATABASE=myapp

.env 文件示例

MYSQL_ROOT_PASSWORD=root123
MYSQL_DATABASE=myapp
MYSQL_USER=user
MYSQL_PASSWORD=password

数据卷

services:
db:
# 命名卷
volumes:
- db-data:/var/lib/mysql

# 绑定挂载
volumes:
- ./data:/var/lib/mysql

# 匿名卷
volumes:
- /var/lib/mysql

# 只读挂载
volumes:
- ./config:/etc/mysql/conf.d:ro

网络配置

services:
web:
# 指定网络
networks:
- frontend
- backend

# 设置网络别名
networks:
frontend:
aliases:
- app.local

networks:
frontend:
backend:

依赖关系

services:
web:
depends_on:
- db
- redis

# 等待条件(需要 healthcheck)
depends_on:
db:
condition: service_healthy
redis:
condition: service_started

健康检查

services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

资源限制

services:
web:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M

网络配置

默认网络

Docker Compose 默认会创建一个网络,所有服务都连接到这个网络:

services:
web:
image: nginx
db:
image: mysql

# 自动创建 default 网络,服务之间可以通过服务名互相访问

自定义网络

services:
web:
networks:
- frontend

api:
networks:
- frontend
- backend

db:
networks:
- backend

networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,无法访问外网

使用已存在的网络

networks:
existing-network:
external: true

数据卷配置

命名卷

services:
db:
volumes:
- db-data:/var/lib/mysql

volumes:
db-data:
driver: local

绑定挂载

services:
web:
volumes:
- ./app:/app
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro

使用已存在的卷

volumes:
existing-volume:
external: true

实战示例

Web 应用栈

# compose.yaml
services:
# Web 前端
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./static:/usr/share/nginx/html:ro
depends_on:
- api
networks:
- frontend

# API 服务
api:
build: ./api
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: postgres://user:pass@db:5432/myapp
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
- backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3

# 数据库
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 10s
timeout: 5s
retries: 5

# 缓存
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

networks:
frontend:
backend:

volumes:
postgres-data:
redis-data:

开发环境

# compose.dev.yaml
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
environment:
NODE_ENV: development
volumes:
- .:/app
- /app/node_modules
command: npm run dev

db:
image: postgres:15-alpine
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
POSTGRES_DB: devdb
ports:
- "5432:5432"
volumes:
- dev-db-data:/var/lib/postgresql/data

adminer:
image: adminer
ports:
- "8080:8080"

volumes:
dev-db-data:

WordPress

services:
wordpress:
image: wordpress:latest
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress-data:/var/www/html
depends_on:
- db

db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
volumes:
- db-data:/var/lib/mysql

volumes:
wordpress-data:
db-data:

常用命令

启动和停止

# 启动所有服务
docker compose up

# 后台启动
docker compose up -d

# 构建并启动
docker compose up --build

# 启动特定服务
docker compose up nginx db

# 停止所有服务
docker compose down

# 停止并删除数据卷
docker compose down -v

# 停止但不删除容器
docker compose stop

# 启动已停止的服务
docker compose start

# 重启服务
docker compose restart

查看状态

# 查看运行中的服务
docker compose ps

# 查看日志
docker compose logs

# 实时查看日志
docker compose logs -f

# 查看特定服务日志
docker compose logs nginx

# 查看资源使用
docker compose top

执行命令

# 在服务中执行命令
docker compose exec nginx bash

# 以 root 用户执行
docker compose exec -u root nginx bash

# 运行一次性命令
docker compose run --rm npm install

其他命令

# 拉取镜像
docker compose pull

# 构建镜像
docker compose build

# 推送镜像
docker compose push

# 验证配置文件
docker compose config

# 查看服务镜像
docker compose images

# 暂停和恢复
docker compose pause
docker compose unpause

高级特性

Profiles(服务配置组)

Profiles 允许你将服务分组,按需启动不同的服务组合:

services:
# 始终启动的核心服务
app:
image: myapp
ports:
- "3000:3000"

# 开发环境专用服务
db:
image: postgres
profiles:
- dev
ports:
- "5432:5432"

adminer:
image: adminer
profiles:
- dev
- debug
ports:
- "8080:8080"

# 调试工具
debug-tool:
image: nicolaka/netshoot
profiles:
- debug
command: sleep infinity

使用 profiles

# 只启动核心服务(无 profiles)
docker compose up -d

# 启动 dev 配置组
docker compose --profile dev up -d

# 启动多个配置组
docker compose --profile dev --profile debug up -d

# 启动特定服务(即使有 profiles)
docker compose up app adminer

# 查看所有服务(包括未启用的 profiles)
docker compose config --services

典型应用场景

services:
app:
image: myapp

# 测试专用数据库
test-db:
image: postgres
profiles:
- test

# 性能测试工具
k6:
image: loadimpact/k6
profiles:
- load-test
volumes:
- ./scripts:/scripts

# 监控栈
prometheus:
image: prom/prometheus
profiles:
- monitoring

grafana:
image: grafana/grafana
profiles:
- monitoring

depends_on 高级配置

除了简单的服务依赖,还支持条件检查:

services:
web:
image: nginx
depends_on:
db:
condition: service_healthy
redis:
condition: service_started

db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
# service_healthy 依赖此配置

redis:
image: redis
# service_started 是默认条件,无需 healthcheck

依赖条件类型

条件说明
service_started服务已启动(默认)
service_healthy服务健康检查通过
service_completed_successfully服务成功完成并退出

等待初始化容器完成

services:
# 初始化容器
init-db:
image: postgres:15
volumes:
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
command: >
sh -c "postgres && pg_isready && psql -c 'CREATE DATABASE myapp'"
depends_on:
db:
condition: service_healthy

# 主应用等待初始化完成
app:
image: myapp
depends_on:
init-db:
condition: service_completed_successfully

扩展字段(YAML Anchor)

使用 YAML 锚点复用配置:

# 定义共享配置
x-common-env: &common-env
TZ: Asia/Shanghai
LOG_LEVEL: info

x-common-healthcheck: &common-healthcheck
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

services:
app:
image: myapp
environment:
<<: *common-env
APP_NAME: app1
healthcheck:
<<: *common-healthcheck
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]

api:
image: myapi
environment:
<<: *common-env
APP_NAME: api1
healthcheck:
<<: *common-healthcheck
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]

include 引入其他配置文件

Docker Compose 支持引入其他配置文件:

# compose.yaml
include:
- ./docker/compose.database.yaml
- ./docker/compose.cache.yaml
- ./docker/compose.monitoring.yaml

services:
app:
image: myapp
depends_on:
- db
- redis

database.yaml

services:
db:
image: postgres:15
volumes:
- db-data:/var/lib/docker

volumes:
db-data:

extends 继承服务配置

# common-service.yaml
services:
base:
image: node:18-alpine
working_dir: /app
environment:
NODE_ENV: production
restart: unless-stopped
# compose.yaml
services:
api:
extends:
file: common-service.yaml
service: base
command: node api.js
ports:
- "3000:3000"

worker:
extends:
file: common-service.yaml
service: base
command: node worker.js

资源配置和约束

services:
app:
image: myapp
deploy:
# 资源限制
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
# 副本数(Swarm 模式)
replicas: 3
# 更新策略
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
# 重启策略
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
# 放置约束
placement:
constraints:
- node.role == manager
- node.labels.region == cn-east

服务扩缩容

# 扩展服务实例
docker compose up -d --scale app=3

# 缩减服务
docker compose up -d --scale app=1

# 使用端口范围
services:
app:
ports:
- "3000-3005:3000" # 支持多实例

构建配置详解

services:
app:
build:
# 构建上下文
context: ./app
# Dockerfile 路径
dockerfile: Dockerfile.prod
# 构建参数
args:
- NODE_VERSION=18
- BUILD_ENV=production
# 构建缓存来源
cache_from:
- myapp:latest
# 标签
labels:
- "com.example.description=My App"
# 目标阶段(多阶段构建)
target: production
# 额外构建上下文
additional_contexts:
- tools=./tools
# SSH 配置
ssh:
- default

多环境配置

使用多个配置文件

# 基础配置 + 开发环境覆盖
docker compose -f compose.yaml -f compose.dev.yaml up

# 基础配置 + 生产环境覆盖
docker compose -f compose.yaml -f compose.prod.yaml up -d

compose.dev.yaml

services:
app:
build:
dockerfile: Dockerfile.dev
volumes:
- .:/app
environment:
NODE_ENV: development

compose.prod.yaml

services:
app:
build:
dockerfile: Dockerfile
environment:
NODE_ENV: production
deploy:
replicas: 3

使用环境变量

services:
app:
image: myapp:${APP_VERSION:-latest}
environment:
DATABASE_URL: ${DATABASE_URL}

.env 文件

APP_VERSION=1.0.0
DATABASE_URL=postgres://localhost:5432/myapp

最佳实践

1. 使用明确的镜像版本

# 不好
image: nginx

# 好
image: nginx:1.24-alpine

2. 合理命名服务

# 使用有意义的服务名
services:
frontend:
# ...
backend-api:
# ...
database-primary:
# ...
cache-redis:
# ...

3. 配置健康检查

services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

4. 使用网络隔离

services:
web:
networks:
- public
api:
networks:
- public
- private
db:
networks:
- private

networks:
public:
private:
internal: true

5. 合理使用卷

# 开发环境:绑定挂载(实时更新)
volumes:
- ./app:/app

# 生产环境:命名卷(持久化)
volumes:
- app-data:/app/data

小结

本章我们学习了:

  1. Docker Compose 的作用和应用场景
  2. compose.yaml 文件结构
  3. 服务配置:镜像、端口、环境变量、卷、网络
  4. 网络和数据卷配置
  5. 多环境配置方案
  6. 常用命令
  7. 最佳实践

练习

  1. 创建一个包含 Nginx 和 PHP 的 Web 服务栈
  2. 配置服务之间的依赖关系和健康检查
  3. 使用多配置文件管理开发/生产环境
  4. 实现一个完整的 Web 应用栈(前端 + API + 数据库 + 缓存)
  5. 练习常用命令:启动、停止、查看日志、进入容器