Appearance
Docker 部署 Java 微服务架构指南
在微服务架构中,服务数量众多,依赖关系复杂。传统的部署方式(直接在服务器上运行 JAR 包)面临着环境不一致、配置繁琐、扩缩容困难等问题。使用 Docker 容器化部署可以完美解决这些痛点。
本文将以一个典型的微服务架构为例,介绍如何使用 Docker 和 Docker Compose 进行一站式部署。
架构概览
我们将部署以下组件:
- Nacos: 服务注册中心与配置中心
- Gateway: API 网关统一入口
- Basic Service: 基础服务(如用户服务、鉴权服务)
- Business Service: 业务服务(调用基础服务)
服务调用流程:
- 客户端请求 → 所有外部请求首先到达 API Gateway(网关服务)
- 服务注册 → 各微服务启动时向 Nacos 注册自己的服务信息(IP、端口、健康状态等)
- 服务发现 → Gateway 从 Nacos 获取可用的服务实例列表
- 路由转发 → Gateway 根据请求路径将流量转发到对应的微服务:
- 转发到 Basic Service(基础服务,如用户服务、鉴权服务)
- 转发到 Business Service(业务服务)
- 服务间调用 → Business Service 通过 RPC(如 OpenFeign)调用 Basic Service 获取基础数据
NOTE
Nacos 的双重角色:
- 注册中心:管理所有微服务的注册信息,实现服务发现
- 配置中心:集中管理各服务的配置文件,支持动态刷新
1. 准备工作
确保开发环境和服务器已安装:
- Docker: 容器运行时
- Docker Compose: 容器编排工具
验证安装:
bash
docker --version
docker-compose --version2. 编写 Dockerfile
对于 Spring Boot 微服务,我们使用 多阶段构建 来创建精简的生产镜像。
在每个微服务项目(如 gateway、basic-service、business-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-gateway4. 上传镜像到镜像仓库
将镜像推送到私有仓库或公有仓库(如 Docker Hub)。
4.1 登录镜像仓库
bash
# 登录私有仓库
docker login my-registry.com
# 或登录 Docker Hub
docker login4.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:latestIMPORTANT
版本管理建议:
- 使用语义化版本号(如
v1.0.0) - 每次发布打上 Git 标签
latest标签仅用于开发环境,生产环境应使用明确版本号
5. 服务器端部署
在生产服务器上使用 Docker Compose 编排所有服务。
5.1 创建部署目录
bash
mkdir -p /opt/microservices
cd /opt/microservices5.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: 1GIMPORTANT
网络通信关键点:
- 所有服务在同一个 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 -f5.4 验证部署
bash
# 检查 Nacos 控制台
curl http://localhost:8848/nacos
# 检查服务注册情况
# 访问 Nacos 控制台: http://服务器IP:8848/nacos
# 默认账号密码: nacos/nacos
# 测试网关
curl http://localhost/api/health6. 常用运维命令
6.1 日志管理
bash
# 查看特定服务日志
docker-compose logs -f gateway
# 查看最近 100 行日志
docker-compose logs --tail=100 business-service
# 查看所有服务日志
docker-compose logs -f6.2 服务更新
bash
# 更新单个服务
docker-compose pull gateway
docker-compose up -d gateway
# 滚动更新所有服务
docker-compose pull
docker-compose up -d6.3 服务扩缩容
bash
# 扩展业务服务到 3 个实例
docker-compose up -d --scale business-service=3
# 查看扩展后的容器
docker-compose ps6.4 故障排查
bash
# 进入容器内部
docker-compose exec gateway sh
# 查看容器资源使用
docker stats
# 重启特定服务
docker-compose restart basic-service
# 停止并删除所有容器
docker-compose down7. 最佳实践
7.1 镜像优化
- 使用 .dockerignore: 排除
.git、target、*.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 个步骤):
- 编写 Dockerfile → 为每个微服务创建多阶段构建的 Dockerfile
- 本地构建镜像 → 使用
docker build命令构建镜像 - 测试镜像 → 本地运行容器验证功能是否正常
- 推送到镜像仓库 → 将镜像上传到 Docker Hub 或私有仓库
- 服务器拉取镜像 → 在生产服务器上使用
docker pull获取镜像 - Docker Compose 启动 → 通过
docker-compose up -d启动所有服务 - 验证服务 → 检查服务注册、健康检查、接口调用
- 监控运维 → 持续监控日志、性能指标,必要时更新或扩容
通过 Docker 和 Docker Compose,我们将复杂的微服务部署变成了简单的配置文件管理,实现了:
- ✅ 环境一致性: 开发、测试、生产环境完全一致
- ✅ 快速部署: 一键启动所有服务
- ✅ 易于扩展: 通过
--scale轻松扩容 - ✅ 便于维护: 声明式配置,版本可追溯
