Java 部署:K8s Deployment 部署 Spring Boot 应用
👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Java部署这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
- Java 部署:K8s Deployment 部署 Spring Boot 应用 🚀
Java 部署:K8s Deployment 部署 Spring Boot 应用 🚀
在现代云原生架构中,将 Java 应用部署到 Kubernetes(简称 K8s)已成为行业标准。Spring Boot 作为最流行的 Java 微服务框架之一,天然具备轻量、快速启动和内嵌容器等特性,非常适合与 Kubernetes 集成。本文将从零开始,手把手教你如何将一个 Spring Boot 应用打包为 Docker 镜像,并通过 Kubernetes Deployment 进行部署、扩缩容、健康检查和滚动更新。
无论你是刚接触 DevOps 的 Java 开发者,还是希望系统化梳理 K8s 部署流程的工程师,本文都将为你提供实用、可落地的完整指南。我们将涵盖以下核心内容:
- 构建一个简单的 Spring Boot 应用
- 使用 Dockerfile 打包应用镜像
- 编写 Kubernetes Deployment 和 Service 配置
- 配置就绪(Readiness)与存活(Liveness)探针
- 实现滚动更新与回滚策略
- 使用 ConfigMap 和 Secret 管理配置
- 通过 Ingress 暴露服务
- 监控与日志最佳实践
准备好了吗?让我们开启这段云原生之旅!☁️
1. 创建一个简单的 Spring Boot 应用 💻
首先,我们需要一个可运行的 Spring Boot 应用。为了演示,我们创建一个极简的 REST API 服务,它提供两个端点:
/api/hello:返回 “Hello from Spring Boot on Kubernetes!”/actuator/health:健康检查端点(由 Spring Boot Actuator 提供)
1.1 项目结构
使用 Spring Initializr 快速生成项目,选择以下依赖:
- Spring Web
- Spring Boot Actuator
生成的 pom.xml 如下:
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version><relativePath/></parent><groupId>com.example</groupId><artifactId>k8s-springboot-demo</artifactId><version>1.0.0</version><name>k8s-springboot-demo</name><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>1.2 编写控制器
创建一个简单的控制器类:
// src/main/java/com/example/k8sdemo/controller/HelloController.javapackagecom.example.k8sdemo.controller;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassHelloController{@GetMapping("/api/hello")publicStringsayHello(){return"Hello from Spring Boot on Kubernetes! 🌈";}}1.3 配置 Actuator
为了让 Kubernetes 能够进行健康检查,我们需要暴露 /actuator/health 端点。在 application.yml 中添加:
# src/main/resources/application.ymlserver:port:8080management:endpoints:web:exposure:include: health,info endpoint:health:show-details: always 此时,应用启动后可通过以下 URL 访问:
http://localhost:8080/api/hellohttp://localhost:8080/actuator/health
1.4 本地测试
运行应用:
./mvnw spring-boot:run 访问 http://localhost:8080/api/hello,应看到:
Hello from Spring Boot on Kubernetes! 🌈 访问 http://localhost:8080/actuator/health,应返回:
{"status":"UP"}✅ 本地验证通过!
2. 构建 Docker 镜像 🐳
Kubernetes 运行的是容器,因此我们需要将 Spring Boot 应用打包成 Docker 镜像。
2.1 编写 Dockerfile
在项目根目录创建 Dockerfile:
# 使用官方 OpenJDK 17 镜像作为基础 FROM openjdk:17-jdk-slim # 设置工作目录 WORKDIR /app # 复制构建好的 JAR 文件 COPY target/k8s-springboot-demo-1.0.0.jar app.jar # 暴露端口 EXPOSE 8080 # 启动应用 ENTRYPOINT ["java", "-jar", "app.jar"] 💡 优化建议:生产环境中可考虑使用多阶段构建(multi-stage build)或 JLink 减小镜像体积,但本例以简洁为主。
2.2 构建 JAR 和镜像
先构建 JAR:
./mvnw clean package -DskipTests 然后构建 Docker 镜像:
docker build -t k8s-springboot-demo:1.0.0 .验证镜像是否构建成功:
docker images |grep k8s-springboot-demo 2.3 本地运行容器测试
docker run -p 8080:8080 k8s-springboot-demo:1.0.0 再次访问 http://localhost:8080/api/hello,确认容器内应用正常运行。
✅ 注意:如果你使用的是远程 Docker daemon(如 Docker Desktop for Mac/Windows),确保网络可访问。
3. Kubernetes 基础概念回顾 🧠
在正式编写 YAML 之前,简要回顾几个关键概念:
- Pod:K8s 最小调度单元,包含一个或多个容器。
- Deployment:声明式地管理 Pod 副本,支持滚动更新、回滚、扩缩容。
- Service:为一组 Pod 提供稳定的网络入口(ClusterIP、NodePort、LoadBalancer)。
- ConfigMap / Secret:用于解耦配置与代码,分别存储非敏感和敏感数据。
- Ingress:管理外部 HTTP/HTTPS 流量进入集群的规则(需 Ingress Controller 支持)。
我们的目标是:
- 通过 Deployment 启动 3 个 Pod 副本
- 通过 Service 暴露内部服务
- 通过 Ingress 暴露到公网(可选)
- 配置健康探针确保高可用
4. 编写 Kubernetes Deployment 配置 📄
4.1 deployment.yaml
创建 deployment.yaml:
apiVersion: apps/v1 kind: Deployment metadata:name: springboot-app labels:app: springboot-app spec:replicas:3selector:matchLabels:app: springboot-app template:metadata:labels:app: springboot-app spec:containers:-name: springboot-container image: k8s-springboot-demo:1.0.0 ports:-containerPort:8080env:-name: JAVA_OPTS value:"-Xmx512m -Xms256m"resources:requests:memory:"256Mi"cpu:"100m"limits:memory:"512Mi"cpu:"500m"⚠️ 注意:上述image: k8s-springboot-demo:1.0.0是本地镜像。在真实集群中,你需要将镜像推送到镜像仓库(如 Docker Hub、Harbor、ECR 等),并使用完整路径,例如your-registry/k8s-springboot-demo:1.0.0。
4.2 service.yaml
创建 service.yaml,将 Pod 暴露为 ClusterIP 服务:
apiVersion: v1 kind: Service metadata:name: springboot-service labels:app: springboot-app spec:type: ClusterIP selector:app: springboot-app ports:-protocol: TCP port:80targetPort:8080这样,集群内其他服务可通过 http://springboot-service 访问该应用。
4.3 应用配置到集群
假设你已有一个运行中的 Kubernetes 集群(如 Minikube、Kind、EKS、AKS 等),执行:
kubectl apply -f deployment.yaml kubectl apply -f service.yaml 查看状态:
kubectl get pods kubectl get deployments kubectl get services 你应该看到 3 个 Running 状态的 Pod。
5. 配置健康探针:Liveness 与 Readiness 🩺
Kubernetes 通过探针(Probes)判断容器是否健康。两种关键探针:
- Liveness Probe:判断容器是否“活着”。失败则重启容器。
- Readiness Probe:判断容器是否“准备好”接收流量。失败则从 Service 后端移除。
Spring Boot Actuator 提供了 /actuator/health,非常适合做探针端点。
5.1 更新 deployment.yaml
在容器配置中添加探针:
# 在 containers 下添加livenessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:20periodSeconds:10timeoutSeconds:5failureThreshold:3readinessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:10periodSeconds:5timeoutSeconds:3failureThreshold:2完整容器部分如下:
containers:-name: springboot-container image: k8s-springboot-demo:1.0.0 ports:-containerPort:8080env:-name: JAVA_OPTS value:"-Xmx512m -Xms256m"resources:requests:memory:"256Mi"cpu:"100m"limits:memory:"512Mi"cpu:"500m"livenessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:20periodSeconds:10timeoutSeconds:5failureThreshold:3readinessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:10periodSeconds:5timeoutSeconds:3failureThreshold:2📌 参数说明:initialDelaySeconds:容器启动后等待多久开始探测periodSeconds:探测间隔failureThreshold:连续失败多少次才判定为失败
重新应用配置:
kubectl apply -f deployment.yaml Kubernetes 将自动滚动更新 Pod,新 Pod 会启用探针。
6. 滚动更新与版本管理 🔄
Kubernetes Deployment 支持无缝滚动更新。只需修改镜像版本,K8s 会逐步替换旧 Pod。
6.1 修改应用并发布 v1.1.0
假设我们修改 HelloController:
@GetMapping("/api/hello")publicStringsayHello(){return"Hello from Spring Boot v1.1.0 on Kubernetes! 🚀";}重新构建 JAR 和镜像:
./mvnw clean package -DskipTests docker build -t k8s-springboot-demo:1.1.0 .6.2 更新 Deployment 镜像
有两种方式:
方式一:直接编辑 YAML
将 deployment.yaml 中的镜像改为 k8s-springboot-demo:1.1.0,然后:
kubectl apply -f deployment.yaml 方式二:使用 kubectl set image
kubectl set image deployment/springboot-app springboot-container=k8s-springboot-demo:1.1.0 6.3 查看滚动更新过程
kubectl rollout status deployment/springboot-app 输出类似:
Waiting for deployment "springboot-app" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "springboot-app" rollout to finish: 2 out of 3 new replicas have been updated... deployment "springboot-app" successfully rolled out Kubernetes 默认采用 滚动更新策略(RollingUpdate),确保服务不中断。
6.4 回滚到上一版本
如果新版本有问题,可快速回滚:
kubectl rollout undo deployment/springboot-app 查看历史版本:
kubectl rollout history deployment/springboot-app 🔄 滚动更新策略细节:
默认maxUnavailable: 25%,maxSurge: 25%,即最多 25% Pod 不可用,最多超出期望副本数 25%。可在 Deployment 中显式配置。
7. 使用 ConfigMap 和 Secret 管理配置 🔐
硬编码配置是反模式。K8s 提供 ConfigMap(非敏感)和 Secret(敏感)来管理配置。
7.1 使用 ConfigMap 配置应用
假设我们想通过环境变量设置欢迎语:
@RestControllerpublicclassHelloController{@Value("${app.message:Hello from Spring Boot!}")privateString message;@GetMapping("/api/hello")publicStringsayHello(){return message +" 🌈";}}在 application.yml 中引用:
app:message: ${APP_MESSAGE:Default Message}7.2 创建 ConfigMap
创建 configmap.yaml:
apiVersion: v1 kind: ConfigMap metadata:name: springboot-config data:APP_MESSAGE:"Welcome to Kubernetes with ConfigMap! 🎉"应用:
kubectl apply -f configmap.yaml 7.3 在 Deployment 中引用 ConfigMap
更新 deployment.yaml 的容器部分:
env:-name: JAVA_OPTS value:"-Xmx512m -Xms256m"-name: APP_MESSAGE valueFrom:configMapKeyRef:name: springboot-config key: APP_MESSAGE 重新部署后,访问 /api/hello 将显示新消息。
7.4 使用 Secret 管理敏感信息
例如数据库密码:
# 创建 Secret(Base64 编码)echo -n 'mysecretpassword'| base64 # 输出: bXlzZWNyZXRwYXNzd29yZAo=# 创建 secret.yamlapiVersion: v1 kind: Secret metadata:name: db-secret type: Opaque data:DB_PASSWORD: bXlzZWNyZXRwYXNzd29yZAo= 在 Deployment 中引用:
env:-name: DB_PASSWORD valueFrom:secretKeyRef:name: db-secret key: DB_PASSWORD 🔒 安全提示:Secret 仅提供基本编码,不加密。生产环境应结合 Vault、KMS 或 Sealed Secrets 使用。
8. 通过 Ingress 暴露服务到公网 🌐
Service 的 ClusterIP 仅限集群内访问。若需从外部访问,可使用 Ingress。
8.1 安装 Ingress Controller
不同平台安装方式不同。以 Minikube 为例:
minikube addons enable ingress 对于云厂商(如 AWS EKS),通常使用 ALB Ingress Controller;GKE 使用 GCE Ingress。
8.2 创建 Ingress 规则
创建 ingress.yaml:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata:name: springboot-ingress annotations:nginx.ingress.kubernetes.io/rewrite-target: / spec:ingressClassName: nginx # 根据你的 Ingress Controller 调整rules:-host: springboot.example.com http:paths:-path: / pathType: Prefix backend:service:name: springboot-service port:number:80🌐 注意:host字段需解析到你的集群入口 IP。本地测试可修改/etc/hosts:
# 获取 Ingress IP kubectl get ingress # 假设 IP 为 192.168.49.2echo"192.168.49.2 springboot.example.com"|sudotee -a /etc/hosts 然后访问 http://springboot.example.com/api/hello。
8.3 HTTPS 支持(可选)
可通过 cert-manager 自动申请 Let’s Encrypt 证书。参考 cert-manager 官方文档。
9. 应用架构与流量流向图 🗺️
为了更直观理解组件关系,我们使用 Mermaid 绘制架构图:
HTTP/HTTPS
External User
Ingress Controller
Ingress Rule
springboot.example.com
Service: springboot-service
Pod 1
Pod 2
Pod 3
ConfigMap/Secret
该图展示了:
- 外部用户通过域名访问 Ingress Controller
- Ingress 根据规则路由到 Service
- Service 负载均衡到多个 Pod
- Pod 从 ConfigMap/Secret 获取配置
10. 日志与监控最佳实践 📊
可观测性是云原生应用的核心。
10.1 日志收集
Spring Boot 默认输出日志到 stdout/stderr,K8s 会自动收集。可通过以下命令查看:
kubectl logs -l app=springboot-app --tail=100生产环境建议集成:
- EFK Stack(Elasticsearch + Fluentd + Kibana)
- Loki + Promtail + Grafana
10.2 指标监控
Spring Boot Actuator 提供 /actuator/metrics,可暴露给 Prometheus。
添加 Micrometer 依赖:
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId></dependency>暴露 Prometheus 端点:
management:endpoints:web:exposure:include: health,info,metrics,prometheus 然后配置 Prometheus 抓取该端点。
10.3 分布式追踪
集成 OpenTelemetry 或 Spring Cloud Sleuth,实现跨服务追踪。
11. 常见问题与调试技巧 🛠️
11.1 Pod 一直处于 Pending 状态
- 检查资源请求是否超过节点容量:
kubectl describe pod <pod-name> - 检查是否有污点(Taint)或亲和性(Affinity)限制
11.2 应用启动失败
- 查看日志:
kubectl logs <pod-name> - 检查探针是否过早失败(调整
initialDelaySeconds)
11.3 无法访问服务
- 检查 Service Selector 是否匹配 Pod Labels
- 检查 Ingress Host 是否解析正确
- 使用
kubectl port-forward临时调试:
kubectl port-forward svc/springboot-service 8080:80 然后访问 http://localhost:8080
12. 总结与进阶方向 🎯
通过本文,你已经掌握了:
✅ 构建 Spring Boot 应用
✅ 打包 Docker 镜像
✅ 编写 K8s Deployment/Service
✅ 配置健康探针
✅ 实现滚动更新与回滚
✅ 使用 ConfigMap/Secret
✅ 通过 Ingress 暴露服务
✅ 基础可观测性
但这只是起点。下一步可探索:
- Helm Chart:将应用打包为 Helm Chart,实现版本化部署
- GitOps:使用 Argo CD 或 Flux 实现声明式持续交付
- Service Mesh:集成 Istio 或 Linkerd 实现高级流量管理
- Serverless:尝试 Knative 将 Spring Boot 转为事件驱动
Kubernetes 生态庞大而强大,但核心思想始终是:声明式、自动化、弹性、可观测。掌握这些原则,你就能在云原生世界游刃有余。
🌟 延伸阅读:Kubernetes 官方文档Spring Boot on Kubernetes 官方指南Docker 官方最佳实践
愿你的 Java 应用在 Kubernetes 上稳定、高效、优雅地运行!🎉
🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨