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 自动部署等),提升应用的可用性和可维护性。希望本文能为开发者的容器化实践提供有力的参考和帮助。

相关推荐
绘梨衣5479 小时前
Docker+FastAPI+MySQL 项目部署报错汇总
mysql·docker·fastapi
HackTorjan9 小时前
深度神经网络的反向传播与梯度优化原理
人工智能·spring boot·神经网络·机器学习·dnn
百年੭ ᐕ)੭*⁾⁾11 小时前
docker使用neo4j
docker·容器·neo4j
春风有信13 小时前
【2026.05.01】Windows10安装Docker Desktop 4.71.0.0步骤及问题解决
运维·docker·容器
sthnyph17 小时前
docker compose安装redis
redis·docker·容器
W.A委员会18 小时前
Docker基本使用流程
运维·docker·容器
直奔標竿18 小时前
Java开发者AI转型第二十五课!Spring AI 个人知识库实战(四)——RAG来源追溯落地,拒绝AI幻觉
java·开发语言·人工智能·spring boot·后端·spring
gwjcloud19 小时前
Kubernetes从入门到精通(进阶篇)03
云原生·容器·kubernetes
GuokLiu19 小时前
260502-Clawith-Docker安装过程
运维·docker·容器·claw