Docker Compose
本章将详细介绍 Docker Compose,学习如何使用 YAML 文件定义和管理多容器应用,实现容器编排和服务管理。
Docker Compose 简介
什么是 Docker Compose?
Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。通过一个 YAML 文件来配置应用程序的服务,然后使用一个命令就可以创建并启动所有服务。
核心概念
- 服务 (Service):应用程序的一个组件,如 web 服务器、数据库等
- 项目 (Project):由一组关联的服务组成的完整应用
- 网络 (Network):服务间通信的网络环境
- 数据卷 (Volume):数据持久化和共享的存储
Docker Compose 的优势
- 简化部署:一个命令启动整个应用栈
- 环境隔离:每个项目有独立的网络和命名空间
- 服务发现:容器间可以通过服务名互相访问
- 配置管理:统一管理所有服务的配置
- 扩展性:轻松扩展服务实例数量
安装 Docker Compose
Linux 安装
bash
# 方法 1:使用 curl 下载
sudo curl -L "https://github.com/docker/compose/releases/download/v2.12.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 方法 2:使用 pip 安装
pip3 install docker-compose
# 方法 3:使用包管理器(Ubuntu)
sudo apt-get update
sudo apt-get install docker-compose-plugin
# 验证安装
docker-compose --versionWindows 和 macOS
Docker Desktop 已经包含了 Docker Compose,无需单独安装。
docker-compose.yml 文件结构
基本结构
yaml
version: '3.8' # Compose 文件版本
services: # 定义服务
web:
# 服务配置
db:
# 服务配置
volumes: # 定义数据卷(可选)
# 数据卷配置
networks: # 定义网络(可选)
# 网络配置版本对应关系
| Compose 版本 | Docker Engine 版本 |
|---|---|
| 3.8 | 19.03.0+ |
| 3.7 | 18.06.0+ |
| 3.6 | 18.02.0+ |
| 3.5 | 17.12.0+ |
服务配置详解
基本服务配置
yaml
version: '3.8'
services:
web:
# 使用现有镜像
image: nginx:latest
# 或者构建镜像
build: .
# build:
# context: .
# dockerfile: Dockerfile
# 容器名称
container_name: my-web-server
# 端口映射
ports:
- "8080:80"
- "8443:443"
# 环境变量
environment:
- NODE_ENV=production
- DEBUG=false
# 数据卷挂载
volumes:
- ./html:/usr/share/nginx/html
- logs:/var/log/nginx
# 网络
networks:
- frontend
# 依赖关系
depends_on:
- db
# 重启策略
restart: unless-stopped构建配置
yaml
services:
web:
build:
context: . # 构建上下文
dockerfile: Dockerfile.prod # 指定 Dockerfile
args: # 构建参数
- VERSION=1.0
- BUILD_DATE=2023-01-01
target: production # 多阶段构建目标
cache_from: # 缓存来源
- myapp:cache
image: myapp:latest # 构建后的镜像名环境变量配置
yaml
services:
web:
# 方法 1:直接定义
environment:
- NODE_ENV=production
- PORT=3000
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
# 方法 2:使用对象格式
environment:
NODE_ENV: production
PORT: 3000
DATABASE_URL: postgresql://user:pass@db:5432/mydb
# 方法 3:从文件读取
env_file:
- .env
- .env.local
# 方法 4:从主机环境继承
environment:
- NODE_ENV
- DATABASE_URL=${DATABASE_URL}数据卷配置
yaml
services:
web:
volumes:
# 绑定挂载
- ./src:/app/src
- ./config.json:/app/config.json:ro # 只读
# 命名数据卷
- app-data:/app/data
- logs:/var/log
# 匿名数据卷
- /app/node_modules
# tmpfs 挂载
- type: tmpfs
target: /tmp
tmpfs:
size: 100M
# 定义命名数据卷
volumes:
app-data:
driver: local
logs:
driver: local
driver_opts:
type: none
o: bind
device: /host/logs网络配置
yaml
services:
web:
networks:
- frontend
- backend
db:
networks:
- backend
# 定义网络
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不能访问外部依赖关系和启动顺序
yaml
services:
web:
depends_on:
- db
- redis
# 或者使用条件依赖(需要 healthcheck)
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:13
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
redis:
image: redis:alpine实际应用示例
示例 1:Web 应用 + 数据库
yaml
version: '3.8'
services:
# Web 应用服务
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
depends_on:
- db
volumes:
- ./uploads:/app/uploads
networks:
- app-network
restart: unless-stopped
# PostgreSQL 数据库
db:
image: postgres:13
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
restart: unless-stopped
# Redis 缓存
redis:
image: redis:alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- app-network
restart: unless-stopped
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge示例 2:微服务架构
yaml
version: '3.8'
services:
# Nginx 反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- api
- web
networks:
- frontend
restart: unless-stopped
# 前端应用
web:
build:
context: ./frontend
dockerfile: Dockerfile
networks:
- frontend
restart: unless-stopped
# API 服务
api:
build:
context: ./backend
dockerfile: Dockerfile
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/api
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
networks:
- frontend
- backend
restart: unless-stopped
# 数据库
db:
image: postgres:13
environment:
- POSTGRES_DB=api
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- db_data:/var/lib/postgresql/data
networks:
- backend
restart: unless-stopped
# 缓存
redis:
image: redis:alpine
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped
volumes:
db_data:
redis_data:
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true示例 3:开发环境
yaml
version: '3.8'
services:
# 开发服务器
dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
- "9229:9229" # Node.js 调试端口
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/devdb
volumes:
- .:/app
- /app/node_modules # 防止覆盖 node_modules
depends_on:
- db
- redis
networks:
- dev-network
command: npm run dev
# 数据库
db:
image: postgres:13
environment:
- POSTGRES_DB=devdb
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
ports:
- "5432:5432" # 暴露端口用于外部连接
volumes:
- dev_db_data:/var/lib/postgresql/data
networks:
- dev-network
# Redis
redis:
image: redis:alpine
ports:
- "6379:6379"
networks:
- dev-network
# 邮件服务(开发用)
mailhog:
image: mailhog/mailhog
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
networks:
- dev-network
volumes:
dev_db_data:
networks:
dev-network:
driver: bridgeDocker Compose 命令
基本命令
bash
# 启动服务
docker-compose up
# 后台启动
docker-compose up -d
# 启动指定服务
docker-compose up web db
# 构建镜像
docker-compose build
# 构建并启动
docker-compose up --build
# 停止服务
docker-compose stop
# 停止并删除容器
docker-compose down
# 停止并删除容器、网络、数据卷
docker-compose down -v
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs
# 实时查看日志
docker-compose logs -f
# 查看指定服务日志
docker-compose logs web
# 进入容器
docker-compose exec web bash
# 运行一次性命令
docker-compose run web npm install
# 扩展服务实例
docker-compose up --scale web=3
# 重启服务
docker-compose restart
# 暂停服务
docker-compose pause
# 恢复服务
docker-compose unpause高级命令
bash
# 验证配置文件
docker-compose config
# 显示配置(解析变量后)
docker-compose config --services
# 拉取镜像
docker-compose pull
# 推送镜像
docker-compose push
# 查看端口映射
docker-compose port web 80
# 查看服务进程
docker-compose top
# 发送信号
docker-compose kill -s SIGINT web
# 删除停止的容器
docker-compose rm
# 强制删除
docker-compose rm -f环境管理
多环境配置
bash
# 开发环境
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# 生产环境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
# 测试环境
docker-compose -f docker-compose.yml -f docker-compose.test.yml up配置文件示例
docker-compose.yml(基础配置):
yaml
version: '3.8'
services:
web:
build: .
volumes:
- ./app:/app
networks:
- app-network
db:
image: postgres:13
networks:
- app-network
networks:
app-network:docker-compose.dev.yml(开发环境覆盖):
yaml
version: '3.8'
services:
web:
ports:
- "3000:3000"
environment:
- NODE_ENV=development
command: npm run dev
db:
ports:
- "5432:5432"
environment:
- POSTGRES_DB=devdb
- POSTGRES_USER=dev
- POSTGRES_PASSWORD=devpassdocker-compose.prod.yml(生产环境覆盖):
yaml
version: '3.8'
services:
web:
ports:
- "80:3000"
environment:
- NODE_ENV=production
restart: unless-stopped
db:
environment:
- POSTGRES_DB=proddb
- POSTGRES_USER=prod
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- prod_db_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
prod_db_data:环境变量文件
.env 文件:
bash
# 数据库配置
DB_PASSWORD=secretpassword
DB_NAME=myapp
DB_USER=postgres
# 应用配置
APP_PORT=3000
APP_ENV=production
# 外部服务
REDIS_URL=redis://redis:6379
API_KEY=your-api-key在 docker-compose.yml 中使用:
yaml
version: '3.8'
services:
web:
ports:
- "${APP_PORT}:3000"
environment:
- NODE_ENV=${APP_ENV}
- API_KEY=${API_KEY}
db:
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}网络和服务发现
默认网络
Docker Compose 自动创建一个默认网络,所有服务都连接到这个网络:
yaml
version: '3.8'
services:
web:
image: nginx
# 可以通过 'db' 访问数据库服务
db:
image: postgres
# 可以通过 'web' 访问 Web 服务自定义网络
yaml
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
- backend
api:
image: myapi
networks:
- backend
db:
image: postgres
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络外部网络
yaml
version: '3.8'
services:
web:
image: nginx
networks:
- existing-network
networks:
existing-network:
external: true数据持久化
命名数据卷
yaml
version: '3.8'
services:
db:
image: postgres
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
driver: local
driver_opts:
type: none
o: bind
device: /host/path/to/data外部数据卷
yaml
version: '3.8'
services:
db:
image: postgres
volumes:
- existing_volume:/var/lib/postgresql/data
volumes:
existing_volume:
external: true健康检查和依赖管理
健康检查
yaml
version: '3.8'
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 30s
timeout: 5s
retries: 5等待依赖服务
使用 wait-for-it 脚本:
yaml
version: '3.8'
services:
web:
build: .
depends_on:
- db
command: ["./wait-for-it.sh", "db:5432", "--", "npm", "start"]
db:
image: postgres扩展和负载均衡
服务扩展
bash
# 扩展 web 服务到 3 个实例
docker-compose up --scale web=3
# 扩展多个服务
docker-compose up --scale web=3 --scale worker=2负载均衡配置
yaml
version: '3.8'
services:
nginx:
image: nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web
web:
build: .
# 不暴露端口,只通过 nginx 访问
# nginx.conf 配置负载均衡
upstream backend {
server web_web_1:3000;
server web_web_2:3000;
server web_web_3:3000;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}监控和日志
日志配置
yaml
version: '3.8'
services:
web:
image: nginx
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
app:
build: .
logging:
driver: "syslog"
options:
syslog-address: "tcp://192.168.1.42:123"监控服务
yaml
version: '3.8'
services:
# 应用服务
web:
build: .
ports:
- "3000:3000"
# Prometheus 监控
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
# Grafana 可视化
grafana:
image: grafana/grafana
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
volumes:
grafana_data:故障排查
常见问题
- 服务无法启动
bash
# 查看详细日志
docker-compose logs service_name
# 检查配置
docker-compose config
# 查看服务状态
docker-compose ps- 网络连接问题
bash
# 检查网络
docker network ls
docker network inspect project_default
# 测试连接
docker-compose exec web ping db- 数据卷问题
bash
# 查看数据卷
docker volume ls
docker volume inspect project_volume_name
# 检查挂载
docker-compose exec service_name df -h- 端口冲突
bash
# 查看端口使用
netstat -tulpn | grep :8080
# 修改端口映射
ports:
- "8081:80" # 使用不同的主机端口本章小结
本章全面介绍了 Docker Compose 的使用:
关键要点:
- 服务编排:使用 YAML 文件定义多容器应用
- 网络管理:服务发现和网络隔离
- 数据管理:数据卷和持久化存储
- 环境管理:多环境配置和变量管理
- 扩展性:服务扩展和负载均衡
- 监控调试:日志管理和故障排查
最佳实践:
- 使用版本控制管理 Compose 文件
- 合理设计服务间的依赖关系
- 使用健康检查确保服务可用性
- 分离配置和代码
- 定期备份重要数据
在下一章中,我们将学习 Docker 的安全最佳实践,包括镜像安全、容器安全和网络安全。