Spring Boot 容器化:Docker+K8s 部署最佳实践

在微服务架构盛行的当下,Spring Boot 因简化开发、快速迭代的特性成为主流开发框架。而容器化部署(Docker)与编排(K8s)则解决了微服务部署中的环境一致性、弹性伸缩、故障自愈等核心问题。本文将从实践出发,详细讲解 Spring Boot 应用从 Docker 镜像构建到 K8s 部署的完整流程,包含可直接复用的示例代码,并拓展镜像优化、K8s 进阶配置等实用技巧,帮助开发者快速掌握容器化部署的最佳实践。

一、前置知识与环境准备

在开始实践前,需确保本地环境已完成以下工具的安装与配置,避免后续操作中出现环境兼容问题:

  • JDK 8+:Spring Boot 应用开发与运行基础,需配置 JAVA_HOME 环境变量

  • Maven/Gradle:项目构建工具,本文以 Maven 为例

  • Docker:容器化核心工具,支持镜像构建与容器运行(Windows 建议使用 WSL2 后端,Mac 直接安装 Docker Desktop)

  • K8s 集群:用于应用编排,本地可使用 Minikube、Kind 或 Docker Desktop 内置的 K8s;生产环境建议使用云厂商集群(阿里云 ACK、腾讯云 TKE 等)

  • kubectl:K8s 命令行工具,用于与 K8s 集群交互,需配置集群访问权限(~/.kube/config)

验证环境:执行 docker --versionkubectl cluster-info 命令,若输出正常则说明环境配置完成。

二、Spring Boot 示例项目搭建

为简化演示,我们搭建一个基础的 Spring Boot Web 项目,提供一个测试接口,用于后续容器化验证。

2.1 项目初始化(使用 Spring Initializr)

访问 Spring Initializr,配置如下:

  • Project:Maven Project

  • Language:Java

  • Spring Boot:2.7.x(稳定版)

  • Dependencies:Spring Web(核心依赖,用于提供 Web 接口)

下载项目后解压,导入 IDE(IntelliJ IDEA 或 Eclipse)。

2.2 编写测试接口

在项目包下创建 controller 目录,新增 HelloController.java 类,提供一个简单的 GET 接口:

java 复制代码
package com.example.springbootdocker.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 测试接口控制器
 */
@RestController
@RequestMapping("/api")
public class HelloController {

    /**
     * 测试接口:返回容器化部署成功信息
     * @return 字符串响应
     */
    @GetMapping("/hello")
    public String hello() {
        return "Spring Boot 容器化部署成功!Docker + K8s 最佳实践";
    }
}
    

2.3 本地测试项目

运行项目主启动类 SpringBootDockerApplication.java,启动成功后,访问 http://localhost:8080/api/hello,若能正常返回响应内容,则说明项目搭建无误。

三、Docker 构建 Spring Boot 镜像(核心步骤)

Docker 镜像作为容器的模板,是容器化部署的基础。构建 Spring Boot 镜像的核心是编写 Dockerfile,定义镜像的构建流程。本节将讲解两种常用的构建方式:基础构建法与多阶段构建法(推荐,可减小镜像体积)。

3.1 基础构建法(适合入门)

3.1.1 编写 Dockerfile

在项目根目录下创建Dockerfile 文件(无后缀),内容如下,每一行都附带详细注释:

dockerfile 复制代码
### 第一步:指定基础镜像(Java 运行环境)
# 选择 openjdk 8 镜像(与项目 JDK 版本一致),alpine 版本体积更小
FROM openjdk:8-jre-alpine

### 第二步:设置工作目录(容器内的目录,类似本地的工作文件夹)
WORKDIR /app

### 第三步:复制本地构建好的 Jar 包到容器内
# 注意:此处 Jar 包名称需与 Maven 构建后的名称一致(可在 pom.xml 中配置固定名称)
# 格式:COPY 本地文件路径 容器内目标路径
COPY target/spring-boot-docker-0.0.1-SNAPSHOT.jar app.jar

### 第四步:暴露容器端口(仅声明,不实际映射,用于文档说明)
# 与 Spring Boot 项目配置的 server.port 一致(默认 8080)
EXPOSE 8080

### 第五步:设置容器启动命令(运行 Jar 包)
# ENTRYPOINT 用于指定容器启动的固定命令,不可被覆盖
ENTRYPOINT ["java", "-jar", "app.jar"]
    

3.1.2 配置 Maven 固定 Jar 包名称

默认情况下,Maven 构建的 Jar 包名称包含版本号和 SNAPSHOT 后缀,不利于 Dockerfile 中统一引用。可在pom.xml 中添加配置,固定 Jar 包名称:

xml 复制代码
<build>
    &lt;finalName&gt;spring-boot-app&lt;/finalName&gt;  <!-- 固定 Jar 包名称为 spring-boot-app.jar -->
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
    

3.1.3 构建 Docker 镜像

首先使用 Maven 构建项目,生成 Jar 包:

bash 复制代码
mvn clean package -Dmaven.test.skip=true  # 跳过测试,快速构建
    

构建成功后,项目根目录的 target 文件夹下会生成 spring-boot-app.jar 文件。接着执行 Docker 构建命令:

bash 复制代码
# 格式:docker build -t 镜像名称:版本号 构建上下文路径(. 表示当前目录)
docker build -t spring-boot-app:v1.0 .
    

构建完成后,执行 docker images 命令,若能看到 spring-boot-app:v1.0 镜像,则说明构建成功。

3.1.4 本地运行 Docker 容器验证

使用构建好的镜像启动容器,映射本地端口 8080 到容器端口 8080:

bash 复制代码
docker run -d -p 8080:8080 --name spring-boot-container spring-boot-app:v1.0
    

参数说明:

  • -d:后台运行容器

  • -p 8080:8080:端口映射,格式为 本地端口:容器端口

  • --name:指定容器名称,便于后续管理

验证:访问 http://localhost:8080/api/hello,若返回正常响应,说明容器运行无误。可通过 docker logs spring-boot-container 查看容器运行日志。

3.2 多阶段构建法(推荐,镜像瘦身)

基础构建法存在一个问题:构建过程依赖本地已构建好的 Jar 包,且若本地环境与构建环境不一致,可能导致镜像构建失败。多阶段构建法可在 Dockerfile 中完成 "项目构建 → 生成 Jar 包 → 构建运行镜像" 的全流程,且能大幅减小镜像体积(仅保留运行所需的 JRE 环境,删除构建依赖)。

3.2.1 编写多阶段 Dockerfile

dockerfile 复制代码
### 第一阶段:构建阶段(使用 Maven 镜像构建项目,生成 Jar 包)
FROM maven:3.6.3-openjdk-8 AS build  # 命名为 build 阶段,后续可引用
WORKDIR /project
COPY pom.xml .  # 先复制 pom.xml,利用 Docker 缓存机制(依赖不变时无需重新下载)
COPY src ./src  # 复制项目源码
RUN mvn clean package -Dmaven.test.skip=true  # 构建项目,生成 Jar 包到 target 目录

### 第二阶段:运行阶段(使用轻量的 JRE 镜像,仅保留运行所需文件)
FROM openjdk:8-jre-alpine
WORKDIR /app
# 从构建阶段复制 Jar 包到当前阶段(仅复制最终产物,减小镜像体积)
COPY --from=build /project/target/spring-boot-app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
    

优势说明:多阶段构建的镜像体积通常比基础构建法小 50% 以上(Maven 镜像约 800MB,JRE 镜像仅 100MB 左右),更适合生产环境部署。

3.2.2 构建并验证多阶段镜像

bash 复制代码
docker build -t spring-boot-app:v2.0 .  # 构建多阶段镜像,版本号设为 v2.0
docker run -d -p 8081:8080 --name spring-boot-container-v2 spring-boot-app:v2.0
    

访问 http://localhost:8081/api/hello,验证容器运行正常。执行 docker images 对比 v1.0 和 v2.0 镜像体积,可明显看到 v2.0 更小。

四、K8s 部署 Spring Boot 应用(最佳实践)

Docker 解决了 "打包镜像" 的问题,而 K8s 则解决了 "镜像编排" 的问题(如多实例部署、负载均衡、故障自愈、弹性伸缩等)。本节将讲解 K8s 部署的核心资源(Deployment、Service),并提供完整的 YAML 配置文件。

4.1 K8s 核心资源说明

部署 Spring Boot 应用需用到两个核心资源:

  • Deployment:用于管理 Pod(K8s 最小部署单元,包含一个或多个容器),支持创建、更新、回滚 Pod,实现故障自愈(Pod 异常时自动重启)和扩缩容。

  • Service:用于暴露 Pod 对外访问,解决 Pod 动态变化(IP 不固定)的问题。通过 Service 可实现负载均衡(分发请求到多个 Pod 实例)。

4.2 编写 Deployment YAML 配置

在项目根目录下创建 deployment.yaml 文件,内容如下(附带详细注释):

yaml 复制代码
apiVersion: apps/v1  # API 版本(Deployment 属于 apps 组,v1 为稳定版)
kind: Deployment     # 资源类型:Deployment
metadata:
  name: spring-boot-deploy  # Deployment 名称
  labels:
    app: spring-boot-app    # 标签:用于关联 Service 和 Pod
spec:
  replicas: 2  # 部署的 Pod 实例数量(生产环境建议至少 2 个,保证高可用)
  selector:
    matchLabels:
      app: spring-boot-app  # 选择器:匹配带有 app=spring-boot-app 标签的 Pod
  template:
    metadata:
      labels:
        app: spring-boot-app  # Pod 标签:必须与 selector.matchLabels 一致
    spec:
      containers:
      - name: spring-boot-container  # 容器名称
        image: spring-boot-app:v2.0  # 容器镜像(本地镜像,若为集群需推送至镜像仓库)
        ports:
        - containerPort: 8080  # 容器暴露的端口(与 Spring Boot 端口一致)
        resources:  # 资源限制(避免单个 Pod 占用过多资源,影响其他应用)
          requests:  # 最小资源需求(K8s 调度时确保节点有足够资源)
            cpu: "100m"  # 100m = 0.1 CPU
            memory: "256Mi"  # 256MB 内存
          limits:  # 最大资源限制(超出则会被 K8s 限制或终止)
            cpu: "500m"
            memory: "512Mi"
        livenessProbe:  # 存活探针(检测容器是否存活,失败则重启容器)
          httpGet:
            path: /actuator/health  # Spring Boot Actuator 健康检查接口(需添加依赖)
            port: 8080
          initialDelaySeconds: 60  # 容器启动后延迟 60 秒开始探测
          periodSeconds: 10  # 探测间隔 10 秒
        readinessProbe:  # 就绪探针(检测容器是否就绪,失败则移除 Service 转发)
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 5
    

4.2.1 添加 Spring Boot Actuator 依赖

上述配置中使用了 /actuator/health 健康检查接口,需在 pom.xml 中添加 Actuator 依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
    

并在 application.yml 中配置 Actuator 暴露健康检查接口:

yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include: health  # 暴露 health 接口(默认仅暴露 /actuator/health)
  endpoint:
    health:
      show-details: always  # 显示健康检查详细信息(开发环境用,生产环境建议关闭)
   

重新构建镜像(docker build -t spring-boot-app:v2.0 .),确保健康检查接口可用。

4.3 编写 Service YAML 配置

创建 service.yaml 文件,用于暴露 Deployment 管理的 Pod 对外访问,配置如下:

yaml 复制代码
apiVersion: v1  # API 版本(Service 属于核心组,v1 为稳定版)
kind: Service  # 资源类型:Service
metadata:
  name: spring-boot-service  # Service 名称
spec:
  type: NodePort  # Service 类型:NodePort(适合测试环境,暴露节点端口供外部访问)
  # type: LoadBalancer  # 生产环境推荐使用,云厂商会自动创建负载均衡器
  selector:
    app: spring-boot-app  # 选择器:匹配带有 app=spring-boot-app 标签的 Pod(与 Deployment 一致)
  ports:
  - port: 8080  # Service 暴露的端口(集群内部访问端口)
    targetPort: 8080  # 目标端口(Pod 中容器暴露的端口,与 Deployment 一致)
    nodePort: 30080  # 节点端口(外部访问端口,范围:30000-32767,可自定义)
    

注意:NodePort 类型仅适合测试环境,生产环境建议使用 LoadBalancer 类型(云厂商提供)或 Ingress(统一入口管理)。

4.4 执行 K8s 部署

4.4.1 部署 Deployment 和 Service

使用 kubectl apply 命令执行部署(需确保 K8s 集群正常运行):

bash 复制代码
kubectl apply -f deployment.yaml  # 部署 Deployment
kubectl apply -f service.yaml     # 部署 Service
    

4.4.2 查看部署状态

执行以下命令查看部署状态,确认所有资源正常运行:

bash 复制代码
kubectl get deployments  # 查看 Deployment 状态(READY 应为 2/2,代表 2 个 Pod 就绪)
kubectl get pods         # 查看 Pod 状态(STATUS 应为 Running)
kubectl get services     # 查看 Service 状态(确认 NodePort 为 30080)
    

若 Pod 状态异常,可通过 kubectl describe pod <pod名称> 查看详细日志,排查问题(常见问题:镜像拉取失败、端口占用、健康检查失败等)。

4.4.3 验证应用访问

本地环境(Minikube/Kind/Docker Desktop K8s):直接访问 http://localhost:30080/api/hello,若返回响应内容,则说明部署成功。

集群环境(云厂商):访问 http://<节点IP>:30080/api/hello(需确保节点 30080 端口对外开放)。

五、关键拓展:镜像优化与 K8s 进阶配置

本节将拓展一些实用技巧,帮助优化容器化部署效果,适配生产环境需求。

5.1 Docker 镜像优化技巧

  • 使用更轻量的基础镜像 :优先选择 alpine 版本(如 openjdk:8-jre-alpine),或使用 Distroless 镜像(仅包含应用和运行时依赖,体积更小,安全性更高)。

  • 清理构建残留 :多阶段构建中,在构建阶段清理 Maven 依赖缓存(如 RUN mvn clean package && rm -rf ~/.m2),减小构建阶段镜像体积。

  • 镜像分层缓存:Dockerfile 中,将不变的内容(如复制 pom.xml、下载依赖)放在前面,变化的内容(如复制源码、构建项目)放在后面,利用 Docker 分层缓存机制,加速镜像构建。

  • 使用非 root 用户运行容器 :默认情况下,容器以 root 用户运行,存在安全风险。可在 Dockerfile 中创建普通用户,切换用户运行容器:
    # 在运行阶段添加以下配置 RUN addgroup -S appgroup && adduser -S appuser -G appgroup # 创建用户组和用户 USER appuser # 切换为普通用户运行容器

5.2 K8s 进阶配置技巧

  • 配置 ConfigMap 和 Secret :将 Spring Boot 配置文件(application.yml)或敏感信息(数据库密码、密钥)存储在 K8s ConfigMap/Secret 中,避免硬编码到镜像中,实现配置动态更新。

    示例(ConfigMap 存储 application.yml):apiVersion: v1 kind: ConfigMap metadata: name: spring-boot-config data: application.yml: | server: port: 8080 management: endpoints: web: exposure: include: health 在 Deployment 中挂载 ConfigMap:spec: template: spec: containers: - name: spring-boot-container image: spring-boot-app:v2.0 volumeMounts: - name: config-volume mountPath: /app/config # 挂载路径(Spring Boot 会自动读取 config 目录下的配置) volumes: - name: config-volume configMap: name: spring-boot-config # 关联 ConfigMap 名称

  • 实现弹性伸缩 :通过 K8s HPA(Horizontal Pod Autoscaler)实现 Pod 弹性伸缩,根据 CPU 使用率或自定义指标自动增减 Pod 实例数量:

    `apiVersion: autoscaling/v2

    kind: HorizontalPodAutoscaler

    metadata:

    name: spring-boot-hpa

    spec:

    scaleTargetRef:

    apiVersion: apps/v1

    kind: Deployment

    name: spring-boot-deploy # 关联 Deployment 名称

    minReplicas: 2 # 最小 Pod 数量

    maxReplicas: 10 # 最大 Pod 数量

    metrics:

    • type: Resource
      resource:
      name: cpu
      target:
      type: Utilization
      averageUtilization: 70 # CPU 使用率超过 70% 时自动扩容
      `
  • 配置日志收集 :生产环境需统一收集容器日志,推荐使用 ELK 栈(Elasticsearch + Logstash + Kibana)或云厂商日志服务。可在 Deployment 中配置日志输出路径,挂载日志卷,便于日志收集:
    spec: template: spec: containers: - name: spring-boot-container image: spring-boot-app:v2.0 volumeMounts: - name: log-volume mountPath: /app/logs # 日志输出路径 volumes: - name: log-volume emptyDir: {} # 临时目录(生产环境建议使用 PersistentVolume 持久化)

六、总结

本文详细讲解了 Spring Boot 应用容器化部署的完整流程:从基础环境准备、示例项目搭建,到 Docker 镜像构建(基础构建法与多阶段构建法),再到 K8s 核心资源(Deployment、Service)的部署与验证,最后拓展了镜像优化、K8s 进阶配置等实用技巧。通过本文的实践,开发者可快速掌握 Docker+K8s 部署 Spring Boot 应用的最佳实践,解决环境一致性、弹性伸缩、故障自愈等核心问题。

在实际生产环境中,还需结合业务需求,进一步优化配置(如使用 Ingress 统一入口、配置监控告警、实现 CI/CD 自动部署等),提升应用的可用性和可维护性。希望本文能为开发者的容器化实践提供有力的参考和帮助。

相关推荐
爱编程的小吴5 小时前
华为云 CCE 快速部署 Apollo 配置中心:单 YAML 一站式实现
docker·华为云
天远Date Lab5 小时前
构建金融级风控中台:Java Spring Boot 集成天远借贷风险探查 API 实战
java·大数据·spring boot·金融
学习3人组6 小时前
docker run 命令详解
运维·docker·容器
古城小栈6 小时前
Spring Boot 3.3 整合 AI 工具链:自动生成接口文档
人工智能·spring boot·后端
G_H_S_3_6 小时前
【网络运维】容器、容器架构与docker部署
运维·网络·docker·架构
椰汁菠萝6 小时前
spring boot整合flowable(分库)
spring boot·flowable·分库
码匠君6 小时前
Dante Cloud 升级 Spring Boot 4 经验分享
经验分享·spring boot·后端
大学生资源网7 小时前
基于JavaWeb的邮件收发系统的设计与实现(源码+文档)
java·开发语言·spring boot·mysql·毕业设计·源码·课程设计
IT 行者7 小时前
Spring Boot 4 升级指南:告别RestTemplate,拥抱现代HTTP客户端
spring boot·后端·http