Skip to content

Docker 部署 Java 微服务架构指南

在微服务架构中,服务数量众多,依赖关系复杂。传统的部署方式(直接在服务器上运行 JAR 包)面临着环境不一致、配置繁琐、扩缩容困难等问题。使用 Docker 容器化部署可以完美解决这些痛点。

本文将以一个典型的微服务架构为例,介绍如何使用 Docker 和 Docker Compose 进行一站式部署。

架构概览

我们将部署以下组件:

  1. Nacos: 服务注册中心与配置中心
  2. Gateway: API 网关统一入口
  3. Basic Service: 基础服务(如用户服务、鉴权服务)
  4. Business Service: 业务服务(调用基础服务)

服务调用流程:

  1. 客户端请求 → 所有外部请求首先到达 API Gateway(网关服务)
  2. 服务注册 → 各微服务启动时向 Nacos 注册自己的服务信息(IP、端口、健康状态等)
  3. 服务发现 → Gateway 从 Nacos 获取可用的服务实例列表
  4. 路由转发 → Gateway 根据请求路径将流量转发到对应的微服务:
    • 转发到 Basic Service(基础服务,如用户服务、鉴权服务)
    • 转发到 Business Service(业务服务)
  5. 服务间调用 → Business Service 通过 RPC(如 OpenFeign)调用 Basic Service 获取基础数据

NOTE

Nacos 的双重角色

  • 注册中心:管理所有微服务的注册信息,实现服务发现
  • 配置中心:集中管理各服务的配置文件,支持动态刷新

1. 准备工作

确保开发环境和服务器已安装:

  • Docker: 容器运行时
  • Docker Compose: 容器编排工具

验证安装:

bash
docker --version
docker-compose --version

2. 编写 Dockerfile

对于 Spring Boot 微服务,我们使用 多阶段构建 来创建精简的生产镜像。

在每个微服务项目(如 gatewaybasic-servicebusiness-service)的根目录下创建 Dockerfile:

dockerfile
# ============================================
# 第一阶段: 构建阶段 (Builder)
# ============================================
FROM maven:3.9-eclipse-temurin-17 AS builder

WORKDIR /build

# 先复制 pom.xml 并下载依赖(利用 Docker 缓存层)
COPY pom.xml .
RUN mvn dependency:go-offline

# 复制源码并编译打包
COPY src ./src
RUN mvn clean package -DskipTests

# ============================================
# 第二阶段: 运行阶段 (Runtime)
# ============================================
FROM eclipse-temurin:17-jre-jammy

WORKDIR /app

# 从构建阶段复制 JAR 包
COPY --from=builder /build/target/*.jar app.jar

# 暴露端口 (根据具体服务调整)
EXPOSE 8080

# 设置时区和 JVM 参数
ENV TZ=Asia/Shanghai \
    JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"

# 创建非 root 用户(安全最佳实践)
RUN groupadd -r appuser && useradd -r -g appuser appuser && \
    chown -R appuser:appuser /app
USER appuser

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD curl -f http://localhost:8080/actuator/health || exit 1

# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

TIP

优化建议:

  • 分离依赖下载和代码编译步骤,充分利用 Docker 缓存
  • pom.xml 中指定 <finalName>app</finalName> 统一 JAR 包名称
  • 使用 .dockerignore 排除 target/.git/ 等无关文件

3. 打包镜像

在本地中构建镜像:

3.1 构建各服务镜像

bash
# 构建 Gateway
cd gateway
docker build -t my-registry.com/microservices/gateway:v1.0.0 .

# 构建 Basic Service
cd ../basic-service
docker build -t my-registry.com/microservices/basic-service:v1.0.0 .

# 构建 Business Service
cd ../business-service
docker build -t my-registry.com/microservices/business-service:v1.0.0 .

3.2 验证镜像

bash
# 查看构建的镜像
docker images | grep microservices

# 本地测试运行
docker run -d -p 8080:8080 --name test-gateway \
  my-registry.com/microservices/gateway:v1.0.0

# 查看日志
docker logs -f test-gateway

# 测试完成后清理
docker stop test-gateway && docker rm test-gateway

4. 上传镜像到镜像仓库

将镜像推送到私有仓库或公有仓库(如 Docker Hub)。

4.1 登录镜像仓库

bash
# 登录私有仓库
docker login my-registry.com

# 或登录 Docker Hub
docker login

4.2 推送镜像

bash
# 推送所有服务镜像
docker push my-registry.com/microservices/gateway:v1.0.0
docker push my-registry.com/microservices/basic-service:v1.0.0
docker push my-registry.com/microservices/business-service:v1.0.0

# 同时推送 latest 标签(可选)
docker tag my-registry.com/microservices/gateway:v1.0.0 \
  my-registry.com/microservices/gateway:latest
docker push my-registry.com/microservices/gateway:latest

IMPORTANT

版本管理建议:

  • 使用语义化版本号(如 v1.0.0
  • 每次发布打上 Git 标签
  • latest 标签仅用于开发环境,生产环境应使用明确版本号

5. 服务器端部署

在生产服务器上使用 Docker Compose 编排所有服务。

5.1 创建部署目录

bash
mkdir -p /opt/microservices
cd /opt/microservices

5.2 编写 docker-compose.yml

创建 docker-compose.yml 文件:

yaml
version: '3.8'

# ============================================
# 网络配置
# ============================================
networks:
  microservices-net:
    driver: bridge

# ============================================
# 服务定义
# ============================================
services:
  # ------------------------------------------
  # Nacos (注册中心 & 配置中心)
  # ------------------------------------------
  nacos:
    image: nacos/nacos-server:v2.2.3
    container_name: nacos
    restart: always
    networks:
      - microservices-net
    environment:
      - MODE=standalone              # 单机模式
      - JVM_XMS=256m
      - JVM_XMX=512m
      - NACOS_AUTH_ENABLE=true       # 开启鉴权
      - NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789  # 自定义密钥
    ports:
      - "8848:8848"
      - "9848:9848"
    volumes:
      - ./data/nacos/logs:/home/nacos/logs
      - ./data/nacos/data:/home/nacos/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/v1/console/health/readiness"]
      interval: 30s
      timeout: 10s
      retries: 5

  # ------------------------------------------
  # Gateway (API 网关)
  # ------------------------------------------
  gateway:
    image: my-registry.com/microservices/gateway:v1.0.0
    container_name: gateway
    restart: always
    networks:
      - microservices-net
    ports:
      - "80:8080"                    # 映射到宿主机 80 端口
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - NACOS_SERVER_ADDR=nacos:8848
      - NACOS_NAMESPACE=prod
    depends_on:
      nacos:
        condition: service_healthy   # 等待 Nacos 健康检查通过
    volumes:
      - ./logs/gateway:/app/logs

  # ------------------------------------------
  # Basic Service (基础服务)
  # ------------------------------------------
  basic-service:
    image: my-registry.com/microservices/basic-service:v1.0.0
    container_name: basic-service
    restart: always
    networks:
      - microservices-net
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - NACOS_SERVER_ADDR=nacos:8848
      - NACOS_NAMESPACE=prod
    depends_on:
      nacos:
        condition: service_healthy
    volumes:
      - ./logs/basic:/app/logs
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

  # ------------------------------------------
  # Business Service (业务服务)
  # ------------------------------------------
  business-service:
    image: my-registry.com/microservices/business-service:v1.0.0
    container_name: business-service
    restart: always
    networks:
      - microservices-net
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - NACOS_SERVER_ADDR=nacos:8848
      - NACOS_NAMESPACE=prod
    depends_on:
      nacos:
        condition: service_healthy
      basic-service:
        condition: service_started   # 业务服务依赖基础服务
    volumes:
      - ./logs/business:/app/logs
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

IMPORTANT

网络通信关键点:

  • 所有服务在同一个 Docker 网络中,可通过服务名互相访问
  • 微服务配置中的 Nacos 地址应为 nacos:8848,而非 localhost
  • Gateway 通过 Nacos 发现其他服务,无需直接配置服务地址

5.3 拉取镜像并启动

bash
# 登录镜像仓库
docker login my-registry.com

# 拉取所有镜像
docker-compose pull

# 启动所有服务(后台运行)
docker-compose up -d

# 查看运行状态
docker-compose ps

# 查看所有服务日志
docker-compose logs -f

5.4 验证部署

bash
# 检查 Nacos 控制台
curl http://localhost:8848/nacos

# 检查服务注册情况
# 访问 Nacos 控制台: http://服务器IP:8848/nacos
# 默认账号密码: nacos/nacos

# 测试网关
curl http://localhost/api/health

6. 常用运维命令

6.1 日志管理

bash
# 查看特定服务日志
docker-compose logs -f gateway

# 查看最近 100 行日志
docker-compose logs --tail=100 business-service

# 查看所有服务日志
docker-compose logs -f

6.2 服务更新

bash
# 更新单个服务
docker-compose pull gateway
docker-compose up -d gateway

# 滚动更新所有服务
docker-compose pull
docker-compose up -d

6.3 服务扩缩容

bash
# 扩展业务服务到 3 个实例
docker-compose up -d --scale business-service=3

# 查看扩展后的容器
docker-compose ps

6.4 故障排查

bash
# 进入容器内部
docker-compose exec gateway sh

# 查看容器资源使用
docker stats

# 重启特定服务
docker-compose restart basic-service

# 停止并删除所有容器
docker-compose down

7. 最佳实践

7.1 镜像优化

  • 使用 .dockerignore: 排除 .gittarget*.log 等无关文件
  • 多阶段构建: 分离构建环境和运行环境,减小镜像体积
  • 基础镜像选择: 优先使用官方镜像,如 eclipse-temurin

7.2 安全加固

  • 非 Root 用户: 容器内使用非特权用户运行应用
  • 敏感信息管理: 使用 Docker Secrets 或环境变量注入,避免硬编码
  • 镜像扫描: 定期使用 Trivy 等工具扫描镜像漏洞

7.3 资源管理

  • 资源限制: 在 docker-compose.yml 中配置 CPU 和内存限制
  • 日志轮转: 配置日志驱动,防止日志文件占满磁盘
yaml
logging:
  driver: "json-file"
  options:
    max-size: "100m"
    max-file: "3"

7.4 监控与健康检查

  • 健康检查: 为每个服务配置 HEALTHCHECK,确保容器真正就绪
  • 监控集成: 集成 Prometheus + Grafana 监控微服务指标
  • 链路追踪: 使用 Skywalking 或 Zipkin 进行分布式链路追踪

8. 完整部署流程总结

完整部署流程(8 个步骤):

  1. 编写 Dockerfile → 为每个微服务创建多阶段构建的 Dockerfile
  2. 本地构建镜像 → 使用 docker build 命令构建镜像
  3. 测试镜像 → 本地运行容器验证功能是否正常
  4. 推送到镜像仓库 → 将镜像上传到 Docker Hub 或私有仓库
  5. 服务器拉取镜像 → 在生产服务器上使用 docker pull 获取镜像
  6. Docker Compose 启动 → 通过 docker-compose up -d 启动所有服务
  7. 验证服务 → 检查服务注册、健康检查、接口调用
  8. 监控运维 → 持续监控日志、性能指标,必要时更新或扩容

通过 Docker 和 Docker Compose,我们将复杂的微服务部署变成了简单的配置文件管理,实现了:

  • 环境一致性: 开发、测试、生产环境完全一致
  • 快速部署: 一键启动所有服务
  • 易于扩展: 通过 --scale 轻松扩容
  • 便于维护: 声明式配置,版本可追溯

最后更新: