Docker Compose作为容器编排的重要工具,极大地简化了多容器应用的管理和部署。本文将全面介绍Docker Compose的使用方法,从基础概念到企业级部署实践。
## Docker Compose基础概念
### Compose文件结构解析
Docker Compose的核心是docker-compose.yml文件,它定义了多容器应用的架构。
```yaml
# docker-compose.yml 基础结构
version: '3.8'
services:
# 服务定义开始
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/app
depends_on:
- db
volumes:
- .:/app
networks:
- app-network
db:
image: postgres:13
environment:
POSTGRES_DB: app
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
redis:
image: redis:6-alpine
networks:<"rat.maicaixia.cn">
- app-network
# 网络定义
networks:
app-network:
driver: bridge
# 卷定义
volumes:
postgres_data:
```
### 基础命令操作
掌握Docker Compose的核心命令是使用的第一步。
```bash
# 启动所有服务
docker-compose up
# 后台启动服务
docker-compose up -d
# 指定compose文件
docker-compose -f docker-compose.prod.yml up -d
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs
docker-compose logs -f web # 跟踪web服务日志
# 停止服务
docker-compose down
# 停止服务并删除卷
docker-compose down -v
# 重启服务
docker-compose restart
# 扩展服务实例
docker-compose up -d --scale web=3
# 执行命令
docker-compose exec web bash
docker-compose exec db psql -U user app
```
## 开发环境配置
### 完整的开发环境示例
为开发团队提供标准化的开发环境。
```yaml
# docker-compose<"high.maicaixia.cn">.dev.yml
version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- ./frontend:/app
- /app/node_modules
environment:
- NODE_ENV=development
- REACT_APP_API_URL=http://localhost:8000/api
depends_on:
- backend
networks:
- app-network
backend:
build:
context: ./backend
dockerfile: Dockerfile.dev
ports:
- "8000:8000"
volumes:
- ./backend:/app
- /app/__pycache__
environment:
- DEBUG=True
- DATABASE_URL=postgresql://devuser:devpass@db:5432/devdb
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
networks:
- app-network
db:
image: postgres:13
environment:
POSTGRES_DB: devdb
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpass
ports:
- "5432:5432" # 方便本地连接
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
redis:
image: redis:6-alpine
ports:
- "6379:6379"
networks:
- app-network
# 开发工具
mailhog:
image: mailhog/mailhog<"neixit.maicaixia.cn">
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
networks:
- app-network
volumes:
postgres_data:
networks:
app-network:
driver: bridge
```
### 开发环境启动脚本
```bash
#!/bin/bash
# dev-setup.sh
set -e
echo "=== 开发环境设置 ==="
# 检查Docker是否运行
if ! docker info > /dev/null 2>&1; then
echo "错误: Docker守护进程未运行"
exit 1
fi
# 创建环境文件
if [ ! -f .env.dev ]; then
cat > .env.dev << EOF
# 开发环境配置
COMPOSE_PROJECT_NAME=myapp_dev
DEBUG=True
DATABASE_URL=postgresql://devuser:devpass@db:5432/devdb
REDIS_URL=redis://redis:6379/0
EOF
echo "创建 .env.dev 文件"
fi
# 构建并启动服务
echo "构建和启动开发环境..."
docker-compose -f docker-compose.dev.yml up -d --build
echo "等待服务启动..."
sleep 10
# 检查服务状态
echo "服务状态:"
docker-compose <"note.maicaixia.cn">-f docker-compose.dev.yml ps
# 运行数据库迁移
echo "运行数据库迁移..."
docker-compose -f docker-compose.dev.yml exec backend python manage.py migrate
echo "开发环境就绪!"
echo "前端: http://localhost:3000"
echo "后端API: http://localhost:8000"
echo "邮件测试: http://localhost:8025"
```
## 生产环境配置
### 生产级Compose配置
生产环境需要关注性能、安全和可靠性。
```yaml
# docker-compose.prod.yml
version: '3.8'
services:
nginx:
image: nginx:1.21-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- static_volume:/app/static
- media_volume:/app/media
depends_on:
- web
networks:
- app-network
restart: unless-stopped
web:
build:
context: .
dockerfile: Dockerfile.prod
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379/0
- DEBUG=False
- SECRET_KEY<"ill.maicaixia.cn">=${SECRET_KEY}
volumes:
- static_volume:/app/static
- media_volume:/app/media
depends_on:
- db
- redis
networks:
- app-network
restart: unless-stopped
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
celery_worker:
build:
context: .
dockerfile: Dockerfile.prod
command: celery -A app worker -l info
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
networks:
- app-network
restart: unless-stopped
deploy:
replicas: 2
celery_beat:
build:
context: .
dockerfile: Dockerfile.prod
command: celery -A app beat -l info
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
networks:
- app-network
restart: unless-stopped
db:
image: postgres:13
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backups:/backups
networks:
- app-network
restart: unless-stopped
command: >
postgres
-c shared_preload<"buzzword.maicaixia.cn">_libraries=pg_stat_statements
-c pg_stat_statements.track=all
-c max_connections=200
redis:
image: redis:6-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- app-network
restart: unless-stopped
volumes:
postgres_data:
redis_data:
static_volume:
media_volume:
networks:
app-network:
driver: bridge
```
### 生产环境部署脚本
```bash
#!/bin/bash
# deploy-prod.sh
set -e
ENV_FILE=".env.prod"
COMPOSE_FILE="docker-compose.prod.yml"
echo "=== 生产环境部署 ==="
# 检查环境文件
if [ ! -f "$ENV_FILE" ]; then
echo "错误: 找不到环境文件 $ENV_FILE"
exit 1
fi
# 加载环境变量
export $(grep -v '^#' $ENV_FILE | xargs)
# 创建必要的目录
mkdir -p nginx/ssl backups
# 生成SSL证书(如果不存在)
if [ ! -f nginx/ssl/cert.pem ]; then
echo "生成自签名SSL证书..."
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout nginx/ssl/key.pem \
-out nginx/ssl/cert.pem \
-subj "/C=US/ST<"iron.maicaixia.cn">=State/L=City/O=Org/CN=example.com"
fi
# 停止现有服务
echo "停止现有服务..."
docker-compose -f $COMPOSE_FILE down
# 拉取最新镜像
echo "拉取最新镜像..."
docker-compose -f $COMPOSE_FILE pull
# 启动服务
echo "启动服务..."
docker-compose -f $COMPOSE_FILE up -d
# 健康检查
echo "执行健康检查..."
sleep 30
# 检查服务状态
echo "服务状态:"
docker-compose -f $COMPOSE_FILE ps
# 检查Web服务健康
if curl -f http://localhost/health > /dev/null 2>&1; then
echo "✓ 应用健康检查通过"
else
echo "✗ 应用健康检查失败"
exit 1
fi
echo "生产环境部署完成!"
```
## 多环境配置管理
### 环境特定配置
使用扩展文件管理不同环境的配置。
```yaml
# docker-compose.base.yml - 基础配置
version: '3.8'
services:
web:
build: .
environment:
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:13
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
volumes:
postgres_data:
```
```yaml
# docker-compose.override.yml - 开发环境扩展
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "8000:8000"
volumes:
- .:/app
environment:
- DEBUG=True
- RELOAD=True
db:
ports:
- "5432:5432"
```
```yaml
# docker-compose.prod.yml<"snake.maicaixia.cn"> - 生产环境扩展
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile.prod
restart: unless-stopped
deploy:
replicas: 3
nginx:
image: nginx:1.21-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
networks:
- app-network
restart: unless-stopped
```
### 环境配置脚本
```bash
#!/bin/bash
# env-setup.sh
ENVIRONMENT=${1:-dev}
case $ENVIRONMENT in
dev)
ENV_FILE=".env.dev"
COMPOSE_FILES="-f docker-compose.base.yml -f docker-compose.override.yml"
;;
staging)
ENV_FILE=".env.staging"
COMPOSE_FILES="-f docker-compose.base.yml -f docker-compose.staging.yml"
;;
prod)
ENV_FILE=".env.prod"
COMPOSE_FILES="-f docker-compose.base.yml -f docker-compose.prod.yml"
;;
*)
echo "用法: $0 {dev|staging|prod}"
exit 1
;;
esac
if [ ! -f "$ENV_FILE" ]; then
echo "错误: 找不到环境文件 $ENV_FILE"
echo "请从模板创建: cp .env.example $ENV_FILE"
exit 1
fi
# 设置环境变量
export COMPOSE_PROJECT_NAME="myapp_${ENVIRONMENT}"
export $(grep -v '^#' $ENV_FILE | xargs)
echo "环境: $ENVIRONMENT"
echo "项目: $COMPOSE_PROJECT_NAME"
# 执行docker-compose命令
shift
docker-compose $COMPOSE_FILES "$@"
```
## 企业级部署实践
### 高可用架构
构建支持高可用的生产环境。
```yaml
# docker-compose.ha.yml
version: '3.8'
services:
haproxy:
image: haproxy:2.4
ports:
- "80:80"
- "443:443"
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
- ./ssl:/etc/ssl:ro
networks:
- app-network
restart: unless-stopped
deploy:
replicas: 2
web:
build: .
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379/0
networks:
- app-network
restart: unless-<"tree.maicaixia.cn">stopped
deploy:
replicas: 5
update_config:
parallelism: 2
delay: 10s
order: start-first
rollback_config:
parallelism: 0
order: stop-first
restart_policy:
condition: any
delay: 5s
max_attempts: 3
window: 120s
resources:
limits:
cpus: '1'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
db:
image: postgres:13
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
restart: unless-stopped
deploy:
placement:
constraints:
- node.role == manager
redis:
image: redis:6-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- app-network
restart: unless-stopped
deploy:
replicas: 3
volumes:
postgres_data:
driver: local
redis_data:
driver: local
networks:
app-network:
driver: overlay
attachable: true
```
### 监控和日志管理
集成监控和日志收集。
```yaml
# docker-compose.monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/console_templates'
- '--storage.tsdb.retention.time=200h'
- '--web.enable-lifecycle'
networks:
- monitoring
restart: unless-stopped
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./grafana/datasources:/etc/grafana/provisioning/datasources
networks:
- monitoring
restart: unless-stopped
depends_on:
- prometheus
node-exporter:
image: prom/node-exporter
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
networks:
- monitoring
restart: unless-stopped
deploy:
mode: global
cadvisor:
image: gcr.io/cadvisor/cadvisor
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
ports:
- "8080:8080"
networks:
- monitoring
restart: unless<"fomo.maicaixia.cn">-stopped
deploy:
mode: global
volumes:
prometheus_data:
grafana_data:
networks:
monitoring:
driver: overlay
```
## 安全最佳实践
### 安全加固配置
```yaml
# docker-compose.secure.yml
version: '3.8'
services:
web:
build: .
user: "1000:1000" # 非root用户
read_only: true
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp
- /var/tmp
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
environment:
- DB_USER_FILE=/run/secrets/db_user
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_user
- db_password
networks:
- app-network
db:
image: postgres:13
user: "999:999" # postgres用户
read_only: false
security_opt:
- no-new-privileges:true
environment:
POSTGRES_DB: myapp
POSTGRES_USER_FILE: /run/secrets/db_user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_user
- db_password
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
secrets:
db_user:
file: ./secrets/db_user.txt
db_password:
file: ./secrets/db_password.txt
volumes:
postgres_data:
networks:
app-network:
driver: bridge
```
### 安全部署脚本
```bash
#!/bin/bash
# secure-deploy.sh
set -e
echo "=== 安全部署检查 ==="
# 检查敏感文件权限
check_file_permissions() {
local file=$1
if [ -f "$file" ]; then
local perm=$(stat -c "%a" "$file")
if [ "$perm" -gt 600 ]; then
echo "警告: $file 权限过宽 ($perm)"
return 1
fi
fi
}
# 检查环境变量
check_env_vars() {
local env_file=$1
if grep -q "PASSWORD\|SECRET\|KEY" "$env_file"; then
echo "警告: $env_file 包含敏感信息"
echo "建议使用Docker Secrets"
fi
}
# 检查镜像签名
check_image_security() {
local image=$1
if ! docker trust inspect "$image" > /dev/null 2>&1; then
echo "警告: $image 未签名"
fi
}
# 执行检查
check_file_permissions ".env.prod"
check_env_vars ".env.prod"
echo "安全检查完成"
```
## 持续集成与部署
### CI/CD集成示例
```yaml
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_DRIVER: overlay2
services:
- docker:dind
before_script:
- apk add --no-cache docker-compose
test:
stage: test
script:
- docker-compose -f docker-compose.test.yml up -d
- docker-compose -f docker-compose.test.yml exec web pytest
- docker-compose -f docker-compose.test.yml down
build:
stage: build
script:
- docker-compose -f docker-compose.prod.yml build
- docker tag myapp_web:latest registry.example.com/myapp/web:${CI_COMMIT_SHA}
- docker push registry.example.com/myapp/web:${CI_COMMIT_SHA}
only:
- main
deploy:
stage: deploy
script:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker-compose -f docker-compose.prod.yml pull
- docker-compose -f docker-compose.prod.yml up -d
- docker-compose -f docker-compose.prod.yml exec web python manage.py migrate
environment:
name: production
url: https://example.com
only:
- main
```
## 结语
Docker Compose作为容器化应用部署的重要工具,从简单的开发环境到复杂的企业级生产部署都能提供有力支持。通过合理的配置管理、安全加固和自动化部署,可以构建出稳定、可靠、易维护的容器化应用架构。
掌握Docker Compose的进阶特性,结合企业实际需求制定合适的部署策略,将显著提升应用交付的效率和质量。随着云原生技术的发展,Docker Compose仍然是容器编排领域不可或缺的重要工具。