Docker Compose 多服务编排实战:从零搭建微服务架构

Docker Compose 多服务编排实战:从零搭建微服务架构

目录

  1. [为什么需要 Docker Compose?](#为什么需要 Docker Compose?)
  2. 实战项目架构
  3. 环境准备
  4. 核心服务搭建
  5. 高级特性:负载均衡与服务发现
  6. [日志集中管理(EFK 栈)](#日志集中管理(EFK 栈))
  7. 生产环境最佳实践
  8. 常见问题排查

为什么需要 Docker Compose?

在单体应用时代,一个容器可能足以运行整个应用。但在微服务架构下,一个完整的应用通常由多个服务组成:Web 前端、API 网关、多个后端服务、数据库、缓存、消息队列等。

手动管理这些容器的痛点:

  • 需要记住每个服务的启动顺序和依赖关系
  • 网络配置复杂,服务间通信困难
  • 环境不一致导致"在我机器上能跑"的问题
  • 日志分散在各个容器,难以排查问题

Docker Compose 通过一个简单的 YAML 文件定义多容器应用,一条命令即可启动整个技术栈。


实战项目架构

我们将构建一个完整的电商微服务系统,包含以下组件:

复制代码
┌─────────────────────────────────────────────────────────────┐
│                         Nginx 网关                          │
│                    (负载均衡 + 反向代理)                      │
└─────────────┬───────────────────────────────────────────────┘
              │
    ┌─────────┴──────────┐
    │                    │
┌───▼────┐          ┌────▼────┐
│前端服务 │          │ API 网关 │
│(React) │          │(Node.js)│
└────┬───┘          └────┬────┘
     │                   │
     └─────────┬─────────┘
               │
    ┌──────────┼──────────┐
    │          │          │
┌───▼───┐  ┌──▼───┐  ┌───▼───┐
│订单服务 │  │用户服务│  │商品服务 │
│(Java)  │  │(Java) │  │(Java)  │
└───┬───┘  └──┬───┘  └───┬───┘
    │         │          │
    └─────────┼──────────┘
              │
    ┌─────────▼──────────┐
    │                    │
┌───▼────┐          ┌────▼────┐
│PostgreSQL│        │  Redis   │
│(主从集群)│        │ (缓存)   │
└─────────┘          └─────────┘

环境准备

1. 安装 Docker Compose

bash 复制代码
# 验证安装
docker-compose --version

# 如果未安装,使用以下命令(Linux)
curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

2. 项目目录结构

bash 复制代码
mkdir -p ecommerce-platform/{services/{frontend,api-gateway,order-service,user-service,product-service},infra/{postgres,redis,nginx},logs,fluentd/conf}
cd ecommerce-platform
tree -L 2

预期输出:

复制代码
.
├── docker-compose.yml          # 主编排文件
├── docker-compose.prod.yml     # 生产环境覆盖配置
├── docker-compose.efk.yml      # 日志收集栈
├── services/
│   ├── frontend/               # React 前端
│   ├── api-gateway/            # Node.js API 网关
│   ├── order-service/          # Java 订单服务
│   ├── user-service/           # Java 用户服务
│   └── product-service/        # Java 商品服务
├── infra/
│   ├── nginx/                  # Nginx 配置
│   ├── postgres/               # 数据库初始化脚本
│   └── redis/                  # Redis 配置
├── logs/                       # 日志挂载目录
└── fluentd/
    └── conf/
        └── fluent.conf         # Fluentd 收集规则

核心服务搭建

步骤 1:数据库与基础设施

创建 docker-compose.yml 基础层:

yaml 复制代码
version: '3.8'

services:
  # PostgreSQL 主库
  postgres-master:
    image: postgres:15-alpine
    container_name: ecommerce-postgres-master
    environment:
      POSTGRES_USER: ecommerce
      POSTGRES_PASSWORD: ${DB_PASSWORD:-secure_password_123}
      POSTGRES_DB: ecommerce_db
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - postgres-master-data:/var/lib/postgresql/data
      - ./infra/postgres/init-master.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ecommerce -d ecommerce_db"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend-network

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: ecommerce-redis
    command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis-data:/data
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - backend-network

  # 消息队列(RabbitMQ)
  rabbitmq:
    image: rabbitmq:3.12-management-alpine
    container_name: ecommerce-rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: ${MQ_PASSWORD:-admin123}
    ports:
      - "5672:5672"     # AMQP 端口
      - "15672:15672"   # 管理界面
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
    networks:
      - backend-network

volumes:
  postgres-master-data:
  redis-data:
  rabbitmq-data:

networks:
  backend-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

关键配置解析:

  • 健康检查:确保数据库就绪后才启动依赖服务
  • 环境变量 :使用 ${VAR:-default} 语法提供默认值,同时支持外部传入
  • 命名卷:数据持久化,避免容器重启数据丢失
  • 自定义网络:指定 IP 段,避免与现有网络冲突

步骤 2:Java 微服务

以订单服务为例,创建 services/order-service/Dockerfile

dockerfile 复制代码
# 多阶段构建优化镜像大小
FROM eclipse-temurin:17-jdk-alpine AS builder
WORKDIR /app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY src ./src
RUN ./mvnw package -DskipTests

# 运行阶段使用更小的 JRE 镜像
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# 创建非 root 用户提升安全性
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

docker-compose.yml 中添加服务定义:

yaml 复制代码
  # 订单服务
  order-service:
    build:
      context: ./services/order-service
      dockerfile: Dockerfile
    container_name: ecommerce-order-service
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-master:5432/ecommerce_db
      - SPRING_DATASOURCE_USERNAME=ecommerce
      - SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD:-secure_password_123}
      - SPRING_REDIS_HOST=redis
      - SPRING_RABBITMQ_HOST=rabbitmq
      - SERVER_PORT=8080
    depends_on:
      postgres-master:
        condition: service_healthy
      redis:
        condition: service_healthy
      rabbitmq:
        condition: service_started
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '1'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
    networks:
      - backend-network
      - service-network

  # 用户服务(类似配置)
  user-service:
    build:
      context: ./services/user-service
    container_name: ecommerce-user-service
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-master:5432/ecommerce_db
    depends_on:
      postgres-master:
        condition: service_healthy
    networks:
      - backend-network
      - service-network

  # 商品服务
  product-service:
    build:
      context: ./services/product-service
    container_name: ecommerce-product-service
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-master:5432/ecommerce_db
      - SPRING_REDIS_HOST=redis
    depends_on:
      postgres-master:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - backend-network
      - service-network

生产级优化点:

  • 多阶段构建:将编译和运行分离,最终镜像体积减少 60% 以上
  • 资源限制 :通过 deploy.resources 限制 CPU 和内存,防止单个服务耗尽主机资源
  • 非 root 用户:遵循安全最佳实践,减少攻击面
  • JVM 容器感知 :使用 -XX:+UseContainerSupport 让 JVM 正确识别容器内存限制

步骤 3:API 网关(Node.js)

创建 services/api-gateway/Dockerfile

dockerfile 复制代码
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]

添加网关配置:

yaml 复制代码
  api-gateway:
    build: ./services/api-gateway
    container_name: ecommerce-api-gateway
    environment:
      - NODE_ENV=production
      - PORT=3000
      - ORDER_SERVICE_URL=http://order-service:8080
      - USER_SERVICE_URL=http://user-service:8080
      - PRODUCT_SERVICE_URL=http://product-service:8080
      - REDIS_URL=redis://redis:6379
    ports:
      - "3000:3000"
    depends_on:
      - order-service
      - user-service
      - product-service
    networks:
      - backend-network
      - service-network
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

步骤 4:前端与 Nginx 负载均衡

创建 infra/nginx/nginx.conf

nginx 复制代码
upstream api_gateway {
    least_conn;  # 最少连接数负载均衡算法
    server api-gateway:3000 max_fails=3 fail_timeout=30s;
}

upstream order_service {
    least_conn;
    server order-service:8080;
}

server {
    listen 80;
    server_name localhost;

    # 前端静态资源
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    # API 代理
    location /api/ {
        proxy_pass http://api_gateway/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 超时配置
        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 健康检查端点
    location /nginx-health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
}

添加 Nginx 和前端服务:

yaml 复制代码
  # React 前端构建
  frontend:
    build:
      context: ./services/frontend
      dockerfile: Dockerfile
      args:
        - REACT_APP_API_URL=/api
    container_name: ecommerce-frontend
    networks:
      - frontend-network

  # Nginx 网关与负载均衡
  nginx:
    image: nginx:alpine
    container_name: ecommerce-nginx
    ports:
      - "80:80"
    volumes:
      - ./infra/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - frontend
      - api-gateway
    networks:
      - frontend-network
      - service-network

高级特性:负载均衡与服务发现

服务扩展与负载均衡

Docker Compose 支持快速扩展服务实例:

bash 复制代码
# 扩展订单服务为 3 个实例
docker-compose up -d --scale order-service=3

修改 Nginx 配置以支持动态上游:

nginx 复制代码
# 使用变量配合 resolver 实现动态服务发现
resolver 127.0.0.11 valid=30s;  # Docker 内置 DNS

upstream backend {
    zone upstream_backend 64k;
    server order-service:8080 resolve;
}

网络隔离策略

创建分层网络提升安全性:

yaml 复制代码
networks:
  # 外部访问层
  frontend-network:
    driver: bridge
    internal: false
  
  # 服务间通信层
  service-network:
    driver: bridge
    internal: true  # 禁止外部访问
  
  # 数据层(仅数据库和缓存)
  backend-network:
    driver: bridge
    internal: true

网络隔离原则:

  • 数据库和缓存只在 backend-network,不暴露端口到宿主机
  • 微服务同时连接 backend-network(访问数据)和 service-network(服务间通信)
  • Nginx 是唯一暴露 80 端口的入口

日志集中管理(EFK 栈)

当服务数量增加,分散的日志难以排查问题。我们集成 EFK(Elasticsearch + Fluentd + Kibana)实现日志中心化。

创建 docker-compose.efk.yml

yaml 复制代码
version: '3.8'

services:
  elasticsearch:
    image: elasticsearch:8.11.0
    container_name: ecommerce-elasticsearch
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - es-data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    networks:
      - logging-network

  fluentd:
    image: fluent/fluentd:v1.16-1
    container_name: ecommerce-fluentd
    volumes:
      - ./fluentd/conf:/fluentd/etc
      - ./logs:/var/log/fluentd
    ports:
      - "24224:24224"
      - "24224:24224/udp"
    depends_on:
      - elasticsearch
    networks:
      - logging-network

  kibana:
    image: kibana:8.11.0
    container_name: ecommerce-kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - logging-network

volumes:
  es-data:

networks:
  logging-network:
    driver: bridge

创建 fluentd/conf/fluent.conf

xml 复制代码
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

<filter **>
  @type parser
  format json
  key_name log
  reserve_data true
</filter>

<match **>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
  logstash_prefix ecommerce-logs
  flush_interval 10s
</match>

使用方式:

bash 复制代码
# 启动业务服务 + EFK 栈
docker-compose -f docker-compose.yml -f docker-compose.efk.yml up -d

# 配置业务服务日志驱动

在主 docker-compose.yml 中添加日志驱动配置:

yaml 复制代码
  order-service:
    logging:
      driver: "fluentd"
      options:
        fluentd-address: localhost:24224
        tag: "order-service"
        labels: "service_name,environment"

访问 http://localhost:5601 查看 Kibana 界面,创建索引模式 ecommerce-logs-* 即可搜索所有服务日志。


生产环境最佳实践

1. 多环境配置分离

创建 docker-compose.prod.yml 覆盖生产配置:

yaml 复制代码
version: '3.8'

services:
  order-service:
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2'
          memory: 1G
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "10"
    restart: unless-stopped

  postgres-master:
    volumes:
      - /mnt/nfs/postgres-data:/var/lib/postgresql/data  # 使用 NFS 存储
    command: >
      postgres 
      -c max_connections=200
      -c shared_buffers=2GB
      -c effective_cache_size=6GB

启动命令:

bash 复制代码
# 开发环境
docker-compose up -d

# 生产环境(合并配置)
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

2. 敏感信息管理

使用 Docker Secrets(Swarm 模式)或环境变量文件:

bash 复制代码
# .env 文件(加入 .gitignore)
DB_PASSWORD=your_secure_password
JWT_SECRET=your_jwt_secret
yaml 复制代码
  order-service:
    env_file:
      - .env
    secrets:
      - db_password
      - jwt_secret

secrets:
  db_password:
    file: ./secrets/db_password.txt
  jwt_secret:
    file: ./secrets/jwt_secret.txt

3. 健康检查与自动恢复

yaml 复制代码
  order-service:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s  # 启动宽限期
    restart: unless-stopped

4. 资源限制与日志轮转

yaml 复制代码
  nginx:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "service_name,environment"
        env: "OS_VERSION"

常见问题排查

问题 1:服务启动顺序依赖

现象:应用服务启动失败,提示数据库连接超时。

解决 :使用 depends_on 配合健康检查,确保数据库就绪后才启动应用。

yaml 复制代码
depends_on:
  postgres-master:
    condition: service_healthy  # 需要 Docker Compose 2.20+

问题 2:容器间通信失败

现象 :服务 A 无法访问服务 B,提示 Connection refused

排查步骤:

  1. 检查是否在同一网络:docker network inspect backend-network
  2. 检查服务名是否正确(使用容器名而非 localhost)
  3. 检查端口是否暴露(内部通信不需要 ports 映射)

问题 3:数据卷权限错误

现象 :PostgreSQL 启动失败,Permission denied

解决

bash 复制代码
# 宿主机目录赋予容器用户权限
sudo chown -R 999:999 ./postgres-data  # 999 是 postgres 容器用户 ID

问题 4:内存不足 OOM

现象 :容器频繁重启,Exit Code 137

解决:添加 JVM 参数和资源限制:

yaml 复制代码
environment:
  - JAVA_OPTS=-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
deploy:
  resources:
    limits:
      memory: 1G

完整启动流程

bash 复制代码
# 1. 克隆项目并进入目录
git clone <your-repo> && cd ecommerce-platform

# 2. 创建环境变量文件
cat > .env << EOF
DB_PASSWORD=SecureP@ssw0rd123
JWT_SECRET=your-256-bit-secret
EOF

# 3. 构建所有镜像(首次)
docker-compose build

# 4. 启动基础设施(数据库、缓存)
docker-compose up -d postgres-master redis rabbitmq

# 5. 等待数据库就绪
docker-compose exec postgres-master pg_isready -U ecommerce

# 6. 启动业务服务
docker-compose up -d order-service user-service product-service

# 7. 启动网关和前端
docker-compose up -d api-gateway frontend nginx

# 8. 验证状态
docker-compose ps

# 9. 查看日志
docker-compose logs -f order-service

# 10. 压力测试(可选)
docker-compose up -d --scale order-service=3

总结

通过本实战项目,我们掌握了:

多服务编排 :使用 Docker Compose 管理 8+ 个服务的依赖关系

网络设计 :分层网络架构实现安全隔离

负载均衡 :Nginx 反向代理 + 服务扩展

日志收集 :EFK 栈实现中心化日志管理

生产优化:资源限制、健康检查、多阶段构建

Docker Compose 是微服务开发测试阶段的利器,配合 Swarm 或 Kubernetes 可实现生产级容器编排。建议将 Compose 文件纳入版本控制,并通过 CI/CD 流水线自动化部署。


💡 提示:本实战代码已整理为可运行模板,你可以基于此架构快速搭建自己的微服务平台。生产环境建议结合 Docker Swarm 或 Kubernetes 实现更强大的编排能力。

相关推荐
C澒5 小时前
微前端容器标准化:容器标准化能力的 “配置化+ 插件化”
前端·架构
李彦亮老师(本人)13 小时前
【Linux系统】Rocky Linux 9.7操作系统简介
linux·运维·服务器·docker·kubernetes
freewlt14 小时前
深入理解 OpenClaw:打造安全可控的本地 AI 助理架构
人工智能·安全·架构·openclaw
WeeJot嵌入式15 小时前
NVIDIA GTC 2026实战:Rubin平台AI五层架构部署指南
人工智能·架构
T1an-115 小时前
Docker + K8s:现代开发的“标配”
docker·容器·kubernetes
SmartBrain15 小时前
AI深度解析:智能体产品核心理念与技术架构
人工智能·架构·aigc
子兮曰15 小时前
llama.cpp Windows 免编译部署实测:Releases 下载、模型检索与参数详解
人工智能·架构·开源
架构师沉默16 小时前
AI 写的代码,你敢上线吗?
java·后端·架构