Docker Compose编排微服务
引言
Docker Compose是Docker官方提供的容器编排工具,用于定义和运行多容器Docker应用。通过Compose,可以使用YAML文件定义服务、网络、数据卷等资源,然后通过简单的命令启动和停止整个应用。Docker Compose特别适合开发、测试和演示环境,也是微服务架构中进行本地开发和服务编排的重要工具。本文将详细介绍Docker Compose的使用方法、配置技巧以及在微服务架构中的最佳实践。
一、Docker Compose基础
1.1 安装和基本概念
Docker Compose通过docker-compose.yml文件定义应用的服务拓扑。Compose会自动处理服务间的依赖关系、端口映射和网络配置。
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
– "8080:8080"
depends_on:
– db
– redis
environment:
– SPRING_PROFILES_ACTIVE=production
– DB_HOST=db
– REDIS_HOST=redis
networks:
– backend
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
– postgres_data:/var/lib/postgresql/data
networks:
– backend
redis:
image: redis:7-alpine
command: redis-server –appendonly yes
volumes:
– redis_data:/data
networks:
– backend
volumes:
postgres_data:
redis_data:
networks:
backend:
driver: bridge
1.2 常用命令
# 启动所有服务
docker-compose up -d
# 构建镜像并启动
docker-compose up –build
# 启动指定服务
docker-compose up -d web
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f web
# 停止服务
docker-compose down
# 停止并删除卷
docker-compose down -v
# 重启服务
docker-compose restart web
# 执行命令
docker-compose exec web java -jar app.jar
# 扩容服务
docker-compose up -d –scale web=3
二、微服务编排实战
2.1 多服务架构示例
假设我们有一个订单微服务系统,包含以下服务:API网关服务、订单服务、产品服务、用户服务、MySQL数据库、Redis缓存。
version: '3.8'
services:
# API网关
api-gateway:
build:
context: ./api-gateway
dockerfile: Dockerfile
container_name: api-gateway
ports:
– "8080:8080"
environment:
– SPRING_CLOUD_GATEWAY_ROUTES[0].uri=http://order-service:8081
– SPRING_CLOUD_GATEWAY_ROUTES[0].predicates=Path=/orders/**
– SPRING_CLOUD_GATEWAY_ROUTES[1].uri=http://product-service:8082
– SPRING_CLOUD_GATEWAY_ROUTES[1].predicates=Path=/products/**
– SPRING_CLOUD_GATEWAY_ROUTES[2].uri=http://user-service:8083
– SPRING_CLOUD_GATEWAY_ROUTES[2].predicates=Path=/users/**
depends_on:
order-service:
condition: service_healthy
product-service:
condition: service_started
user-service:
condition: service_started
networks:
– microservices
restart: unless-stopped
# 订单服务
order-service:
build:
context: ./order-service
dockerfile: Dockerfile
container_name: order-service
expose:
– "8081"
environment:
– SERVER_PORT=8081
– SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/orders?useSSL=false&serverTimezone=UTC
– SPRING_DATASOURCE_USERNAME=root
– SPRING_DATASOURCE_PASSWORD=rootpassword
– SPRING_REDIS_HOST=redis
– SPRING_REDIS_PORT=6379
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
– microservices
restart: unless-stopped
# 产品服务
product-service:
build:
context: ./product-service
dockerfile: Dockerfile
container_name: product-service
expose:
– "8082"
environment:
– SERVER_PORT=8082
– SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/products?useSSL=false&serverTimezone=UTC
– SPRING_DATASOURCE_USERNAME=root
– SPRING_DATASOURCE_PASSWORD=rootpassword
– SPRING_REDIS_HOST=redis
– SPRING_REDIS_PORT=6379
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
– microservices
restart: unless-stopped
# 用户服务
user-service:
build:
context: ./user-service
dockerfile: Dockerfile
container_name: user-service
expose:
– "8083"
environment:
– SERVER_PORT=8083
– SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/users?useSSL=false&serverTimezone=UTC
– SPRING_DATASOURCE_USERNAME=root
– SPRING_DATASOURCE_PASSWORD=rootpassword
depends_on:
mysql:
condition: service_healthy
networks:
– microservices
restart: unless-stopped
# MySQL数据库
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: orders
ports:
– "3306:3306"
volumes:
– mysql_data:/var/lib/mysql
– ./init-scripts:/docker-entrypoint-initdb.d
command: –default-authentication-plugin=mysql_native_password
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
– microservices
restart: unless-stopped
# Redis缓存
redis:
image: redis:7-alpine
container_name: redis
ports:
– "6379:6379"
volumes:
– redis_data:/data
command: redis-server –appendonly yes –requirepass redispassword
networks:
– microservices
restart: unless-stopped
volumes:
mysql_data:
redis_data:
networks:
microservices:
driver: bridge
三、配置管理
3.1 环境变量文件
创建.env文件管理环境变量,避免在docker-compose.yml中硬编码敏感信息。
# .env文件
COMPOSE_PROJECT_NAME=microservices
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=orders
REDIS_PASSWORD=redispassword
API_GATEWAY_PORT=8080
# docker-compose.yml
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
3.2 多环境配置
# docker-compose.yml
services:
app:
build:
context: .
args:
JAR_FILE: app.jar
environment:
– SPRING_PROFILES_ACTIVE=${PROFILE:-development}
# 使用生产环境配置
PROFILE=production docker-compose up -d
# 使用自定义变量文件
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
3.3 配置继承
# docker-compose.base.yml – 基础配置
version: '3.8'
services:
app:
build: .
networks:
– common
networks:
common:
name: common-network
external: true
# docker-compose.yml – 继承并扩展
version: '3.8'
services:
app:
extends:
file: docker-compose.base.yml
service: app
ports:
– "8080:8080"
四、健康检查和依赖管理
4.1 服务依赖配置
depends_on确保服务启动顺序,但不能保证服务就绪。
services:
web:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
4.2 健康检查配置
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
disable: false
mysql:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
redis:
healthcheck:
test: ["CMD", "redis-cli", "–raw", "incr", "ping"]
interval: 10s
timeout: 5s
retries: 3
五、网络配置
5.1 网络隔离
为不同环境或不同服务组创建独立的网络。
services:
frontend:
networks:
– frontend-network
backend:
networks:
– backend-network
– database-network
database:
networks:
– database-network
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
database-network:
driver: bridge
internal: true # 禁止外部访问
5.2 DNS配置
services:
app:
dns:
– 8.8.8.8
– 8.8.4.4
dns_search:
– mydomain.local
六、资源限制
6.1 内存和CPU限制
services:
app:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
6.2 重启策略
services:
app:
restart: unless-stopped # 总是重启,除非手动停止
# restart: always # 总是重启
# restart: on-failure # 仅在失败时重启
# restart: no # 不自动重启
七、日志管理
7.1 日志配置
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "production"
compress: "true"
7.2 集中式日志收集
services:
app:
logging:
driver: syslog
options:
syslog-address: "tcp://logstash:5000"
tag: "app"
logstash:
image: logstash:7.17
volumes:
– ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
八、持续集成实践
8.1 完整的开发环境
version: '3.8'
services:
# 微服务
order-service:
build: ./order-service
ports:
– "8081:8081"
environment:
– SPRING_PROFILES_ACTIVE=development
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
volumes:
– ./order-service:/app
– maven-cache:/root/.m2
command: mvn spring-boot:run
# 数据存储
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: orders
ports:
– "3306:3306"
volumes:
– mysql_data:/var/lib/mysql
– ./order-service/src/main/resources/db/migration:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
– "6379:6379"
# 开发工具
prometheus:
image: prometheus:latest
ports:
– "9090:9090"
volumes:
– ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:latest
ports:
– "3000:3000"
environment:
– GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
– grafana_data:/var/lib/grafana
volumes:
mysql_data:
redis_data:
maven-cache:
grafana_data:
九、最佳实践
9.1 镜像优化
# 多阶段构建优化
FROM maven:3.8-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY –from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
9.2 安全最佳实践
services:
app:
security_opt:
– no-new-privileges:true
read_only: true
tmpfs:
– /tmp
user: "1000:1000"
9.3 Compose文件组织
project/
├── docker-compose.yml # 主配置
├── docker-compose.dev.yml # 开发环境覆盖
├── docker-compose.prod.yml # 生产环境覆盖
├── docker-compose.test.yml # 测试环境覆盖
├── .env # 环境变量
├── .env.prod # 生产环境变量
├── services/
│ ├── service-a/
│ │ ├── Dockerfile
│ │ └── src/
│ └── service-b/
│ ├── Dockerfile
│ └── src/
└── config/
├── prometheus.yml
└── grafana/
总结
Docker Compose是管理和编排微服务的强大工具,特别适合开发和测试环境。通过合理的配置,可以快速搭建完整的微服务开发环境,实现服务的快速启动和停止。掌握Docker Compose的配置技巧和最佳实践,能够显著提升开发效率。在实际项目中,建议结合环境变量和配置继承来管理不同环境的配置,使用健康检查确保服务依赖的正确性,并通过日志和资源限制来保证系统的可观测性和稳定性。



