在微服务架构盛行的当下,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 --version、kubectl 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 接口:
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 文件(无后缀),内容如下,每一行都附带详细注释:
### 第一步:指定基础镜像(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 包名称:
<build>
<finalname>spring-boot-app</finalname> <!-- 固定 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 包:
mvn clean package -dmaven.test.skip=true # 跳过测试,快速构建
构建成功后,项目根目录的 target 文件夹下会生成 spring-boot-app.jar 文件。接着执行 docker 构建命令:
# 格式:docker build -t 镜像名称:版本号 构建上下文路径(. 表示当前目录) docker build -t spring-boot-app:v1.0 .
构建完成后,执行 docker images 命令,若能看到 spring-boot-app:v1.0 镜像,则说明构建成功。
3.1.4 本地运行 docker 容器验证
使用构建好的镜像启动容器,映射本地端口 8080 到容器端口 8080:
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
### 第一阶段:构建阶段(使用 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 构建并验证多阶段镜像
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 文件,内容如下(附带详细注释):
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: 54.2.1 添加 spring boot actuator 依赖
上述配置中使用了 /actuator/health 健康检查接口,需在 pom.xml 中添加 actuator 依赖:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-actuator</artifactid>
</dependency>并在 application.yml 中配置 actuator 暴露健康检查接口:
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 对外访问,配置如下:
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 集群正常运行):
kubectl apply -f deployment.yaml # 部署 deployment kubectl apply -f service.yaml # 部署 service
4.4.2 查看部署状态
执行以下命令查看部署状态,确认所有资源正常运行:
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 自动部署等),提升应用的可用性和可维护性。希望本文能为开发者的容器化实践提供有力的参考和帮助。
到此这篇关于spring boot 容器化docker+k8s 部署最佳实践的文章就介绍到这了,更多相关springboot docker k8s部署内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论