Java 部署:滚动更新(K8s RollingUpdate 策略)

Java 部署:滚动更新(K8s RollingUpdate 策略)
在这里插入图片描述
👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Java部署这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!

文章目录

Java 部署:滚动更新(K8s RollingUpdate 策略)

在现代云原生应用开发中,持续交付和零停机部署已成为企业级 Java 应用的标配。而 Kubernetes(简称 K8s)作为事实上的容器编排平台,其 RollingUpdate(滚动更新) 策略为实现平滑、安全、无感知的应用升级提供了强大支持。本文将深入探讨如何在 Kubernetes 中对 Java 应用实施滚动更新,涵盖原理、配置、最佳实践、故障处理以及完整的代码与部署示例。

无论你是刚接触 K8s 的 Java 开发者,还是已有一定经验但希望优化部署流程的 DevOps 工程师,本文都将为你提供实用、可落地的指导。让我们从基础开始,逐步构建一个健壮、可维护的滚动更新体系 🚀。


什么是滚动更新(Rolling Update)?

滚动更新是一种渐进式部署新版本应用的策略。它通过逐个替换旧 Pod的方式,确保在整个更新过程中服务始终可用,从而实现零停机(Zero Downtime) 的目标。

在 Kubernetes 中,当你更新一个 Deployment 的镜像版本或配置时,如果策略设置为 RollingUpdate(默认值),K8s 会自动执行以下操作:

  1. 启动一个或多个新版本的 Pod;
  2. 等待新 Pod 就绪(通过就绪探针 Ready Probe 判断);
  3. 将流量从旧 Pod 逐步切换到新 Pod;
  4. 删除一个或多个旧 Pod;
  5. 重复上述过程,直到所有旧 Pod 被替换。

这种“边下边上”的方式,避免了传统“蓝绿部署”或“全量替换”可能带来的服务中断风险。

💡 小知识:Kubernetes 的滚动更新是基于 ReplicaSet 实现的。每次更新 Deployment 时,K8s 会创建一个新的 ReplicaSet,并逐步缩容旧 ReplicaSet、扩容新 ReplicaSet。

为什么 Java 应用特别需要滚动更新?

Java 应用通常具有以下特点,使其对滚动更新有更高需求:

  • 启动时间较长:JVM 预热、Spring Boot 初始化等过程可能需要数秒甚至数十秒;
  • 内存占用高:频繁重启可能导致资源竞争;
  • 有状态中间件依赖:如数据库连接池、缓存客户端等,需优雅关闭;
  • 高可用要求:企业级系统通常要求 99.9% 以上的可用性。

若采用一次性删除所有旧实例再启动新实例的方式,用户将经历明显的请求失败或超时。而滚动更新通过控制并发替换数量,确保始终有足够健康的实例处理请求,极大提升了用户体验和系统稳定性 ✅。


Kubernetes 滚动更新的核心机制

Kubernetes 的滚动更新由两个关键参数控制:

  • maxUnavailable:更新过程中允许不可用的 Pod 最大数量(相对于期望副本数);
  • maxSurge:更新过程中允许超出期望副本数的最大 Pod 数量

这两个参数共同决定了更新的速度与安全性。

默认值

对于一个 replicas: 3 的 Deployment,其默认滚动更新策略如下:

strategy:type: RollingUpdate rollingUpdate:maxUnavailable: 25% maxSurge: 25% 

这意味着:

  • 最多允许 1 个 Pod 不可用(3 × 25% ≈ 0.75 → 向上取整为 1);
  • 最多允许临时增加 1 个 Pod(3 × 25% ≈ 0.75 → 向上取整为 1)。

因此,更新过程可能如下:

  1. 创建 1 个新 Pod(总数变为 4);
  2. 等待新 Pod 就绪;
  3. 删除 1 个旧 Pod(总数回到 3);
  4. 重复直到全部替换。

参数详解

参数类型说明
maxUnavailableint 或百分比更新期间可处于“未就绪”状态的 Pod 数量上限。设为 0 可实现完全无损更新(但需配合 maxSurge > 0)。
maxSurgeint 或百分比允许超过 replicas 设定值的额外 Pod 数量。用于提前启动新实例,加快更新速度。
⚠️ 注意:maxUnavailablemaxSurge 不能同时为 0,否则更新将无法进行。

构建一个支持滚动更新的 Java 应用

为了演示滚动更新,我们先构建一个简单的 Spring Boot 应用,包含健康检查端点。

1. 创建 Spring Boot 项目

使用 Spring Initializr 创建一个 Web 项目,添加 Spring WebSpring Boot Actuator 依赖。

2. 编写主类

// src/main/java/com/example/rollingupdate/DemoApplication.javapackagecom.example.rollingupdate;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[] args){SpringApplication.run(DemoApplication.class, args);}}

3. 添加控制器

// src/main/java/com/example/rollingupdate/HelloController.javapackagecom.example.rollingupdate;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassHelloController{@GetMapping("/hello")publicStringhello(){return"Hello from Java App v1! 🌟";}// 模拟版本信息,便于观察更新效果@GetMapping("/version")publicStringversion(){return"v1.0.0";}}

4. 配置 Actuator 健康端点

application.yml 中启用健康检查端点:

# src/main/resources/application.ymlmanagement:endpoints:web:exposure:include: health,info endpoint:health:show-details: always 

Actuator 默认提供 /actuator/health 端点,返回 {"status":"UP"} 表示应用健康。

5. 构建 Docker 镜像

编写 Dockerfile

# Dockerfile FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"] 

构建并打标签(假设你的 Docker Hub 用户名为 yourname):

./mvnw clean package -DskipTests docker build -t yourname/java-rolling-demo:v1 .docker push yourname/java-rolling-demo:v1 
🔗 你可以参考 Docker 官方文档 了解如何构建镜像。

编写 Kubernetes Deployment 配置

接下来,我们将这个 Java 应用部署到 Kubernetes,并配置滚动更新策略。

deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata:name: java-rolling-demo spec:replicas:3strategy:type: RollingUpdate rollingUpdate:maxUnavailable:1maxSurge:1selector:matchLabels:app: java-rolling-demo template:metadata:labels:app: java-rolling-demo spec:containers:-name: app image: yourname/java-rolling-demo:v1 ports:-containerPort:8080livenessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:30periodSeconds:10readinessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:10periodSeconds:5resources:requests:memory:"256Mi"cpu:"100m"limits:memory:"512Mi"cpu:"200m"---apiVersion: v1 kind: Service metadata:name: java-rolling-demo-svc spec:selector:app: java-rolling-demo ports:-protocol: TCP port:80targetPort:8080type: ClusterIP 

关键配置说明

  • readinessProbe:决定 Pod 是否准备好接收流量。只有当探针成功,Service 才会将请求转发给该 Pod。这对滚动更新至关重要——新 Pod 必须完全就绪后才能加入服务。
  • livenessProbe:用于判断应用是否存活。若失败,K8s 会重启容器。
  • resources:限制资源使用,避免单个 Pod 占用过多资源影响其他实例。
  • maxUnavailable: 1:最多允许 1 个 Pod 不可用(3 个副本时,至少 2 个在线)。
  • maxSurge: 1:允许临时多启动 1 个 Pod,加快更新速度。
📌 重要readinessProbe 是滚动更新平滑性的核心!务必确保其路径能真实反映应用就绪状态。

部署并验证初始状态

应用上述配置:

kubectl apply -f deployment.yaml 

检查 Pod 状态:

kubectl get pods -l app=java-rolling-demo 

输出应类似:

NAME READY STATUS RESTARTS AGE java-rolling-demo-7d5b8c9f45-abc12 1/1 Running 0 2m java-rolling-demo-7d5b8c9f45-def34 1/1 Running 0 2m java-rolling-demo-7d5b8c9f45-ghi56 1/1 Running 0 2m 

测试服务:

# 获取 Service IP(或使用 NodePort/Ingress) kubectl get svc java-rolling-demo-svc # 使用 curl 测试(假设已暴露到外部)curl http://<SERVICE-IP>/version # 返回: v1.0.0

执行滚动更新:从 v1 到 v2

现在,我们准备发布新版本 v2。

1. 修改 Java 应用代码

更新 HelloController.java

@GetMapping("/version")publicStringversion(){return"v2.0.0";// 改为 v2}

并修改欢迎语:

@GetMapping("/hello")publicStringhello(){return"Hello from Java App v2! 🚀";}

2. 构建并推送 v2 镜像

./mvnw clean package -DskipTests docker build -t yourname/java-rolling-demo:v2 .docker push yourname/java-rolling-demo:v2 

3. 触发滚动更新

有两种方式:

方式一:直接修改 Deployment YAML

image 字段改为 yourname/java-rolling-demo:v2,然后执行:

kubectl apply -f deployment.yaml 
方式二:使用 kubectl set image(推荐)
kubectl set image deployment/java-rolling-demo app=yourname/java-rolling-demo:v2 
✅ 这种方式无需修改文件,适合 CI/CD 自动化。

4. 监控更新过程

查看滚动更新状态:

kubectl rollout status deployment/java-rolling-demo 

输出示例:

Waiting for deployment "java-rolling-demo" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "java-rolling-demo" rollout to finish: 2 out of 3 new replicas have been updated... deployment "java-rolling-demo" successfully rolled out 

同时,观察 Pod 变化:

kubectl get pods -w -l app=java-rolling-demo 

你将看到旧 Pod 逐步被终止,新 Pod 逐步启动:

NAME READY STATUS RESTARTS AGE java-rolling-demo-7d5b8c9f45-abc12 1/1 Running 0 5m java-rolling-demo-7d5b8c9f45-def34 1/1 Running 0 5m java-rolling-demo-7d5b8c9f45-ghi56 1/1 Running 0 5m java-rolling-demo-6b8d9f7c54-jkl78 0/1 ContainerCreating 0 1s java-rolling-demo-6b8d9f7c54-jkl78 1/1 Running 0 10s java-rolling-demo-7d5b8c9f45-abc12 1/1 Terminating 0 5m30s ... 

5. 验证新版本

多次调用 /version 接口:

foriin{1..10};docurl -s http://<SERVICE-IP>/version;echo;done

初期可能返回 v1.0.0v2.0.0 混合结果,随着更新完成,最终全部返回 v2.0.0

这正是滚动更新的典型特征:流量逐步切换,用户无感知


可视化滚动更新过程

下面是一个 Mermaid 图表,展示滚动更新中 Pod 状态的变化:

00:0000:0000:0000:0000:0100:0100:0100:0100:0200:0200:02Pod-A (v1)Pod-B (v1)Pod-C (v1)Pod-D (v2)Pod-E (v2)Pod-F (v2)旧 Pod新 PodKubernetes Rolling Update 过程(replicas=3, maxUnavailable=1, maxSurge=1)

💡 图中显示:新 Pod 在旧 Pod 终止前已启动并就绪,确保服务连续性。

滚动更新中的关键保障:探针(Probes)

前面提到,readinessProbe 是滚动更新平滑的关键。让我们深入理解其作用。

Readiness Probe(就绪探针)

  • 作用:告诉 K8s “我准备好接收流量了吗?”
  • 触发时机:Pod 启动后周期性调用。
  • 行为:若失败,Pod 不会被加入 Service 的 Endpoints,即不会收到任何请求
  • Java 应用建议
    • 初始延迟(initialDelaySeconds)应大于应用启动时间(如 Spring Boot 通常 10-30 秒);
    • 路径应返回真实业务就绪状态(如数据库连接成功、缓存初始化完成等)。

Liveness Probe(存活探针)

  • 作用:告诉 K8s “我还活着吗?”
  • 行为:若连续失败,K8s 会重启容器。
  • 注意:不要将复杂逻辑放入 liveness probe,否则可能导致误杀。

示例:增强健康检查

你可以自定义健康指示器,确保只有在所有依赖就绪后才返回 UP:

@ComponentpublicclassDatabaseHealthIndicatorimplementsHealthIndicator{@OverridepublicHealthhealth(){// 检查数据库连接if(isDatabaseConnected()){returnHealth.up().withDetail("database","available").build();}returnHealth.down().withDetail("database","unavailable").build();}}

这样,即使 Spring Boot 启动完成,若数据库未连通,/actuator/health 仍返回 DOWN,Pod 不会接收流量,避免错误请求。

🔗 更多关于 Spring Boot 健康检查的信息,可参考 Spring Boot Actuator 文档

处理滚动更新失败:回滚(Rollback)

尽管我们做了充分准备,但更新仍可能失败(如新版本有 bug、配置错误等)。Kubernetes 提供了便捷的回滚机制。

查看更新历史

kubectl rollout history deployment/java-rolling-demo 

输出:

REVISION CHANGE-CAUSE 1 <none> 2 kubectl set image deployment/java-rolling-demo app=yourname/java-rolling-demo:v2 

回滚到上一版本

kubectl rollout undo deployment/java-rolling-demo 

K8s 会自动将镜像切回 v1,并执行反向滚动更新。

回滚到指定版本

kubectl rollout undo deployment/java-rolling-demo --to-revision=1

自动回滚(高级)

Kubernetes 本身不支持“自动回滚”,但可通过以下方式实现:

  • 结合监控告警:如 Prometheus + Alertmanager 检测到错误率飙升,触发 webhook 执行 kubectl rollout undo
  • 使用 Argo Rollouts:这是一个 K8s 扩展,支持金丝雀发布、自动回滚等高级功能。
🔗 Argo Rollouts 官网 提供了更强大的渐进式交付能力。

优化滚动更新体验的最佳实践

1. 设置合理的探针参数

readinessProbe:httpGet:path: /actuator/health port:8080initialDelaySeconds:20# 根据应用启动时间调整periodSeconds:5timeoutSeconds:3successThreshold:1failureThreshold:3

2. 控制更新速度

  • 若系统敏感,可设置 maxUnavailable: 0maxSurge: 1,确保始终有全部副本在线;
  • 若追求速度,可增大 maxSurge(如 50%),但需注意资源压力。

3. 使用 preStop Hook 实现优雅关闭

在 Java 应用终止前,执行清理操作(如关闭连接池、拒绝新请求):

containers:-name: app image: yourname/java-rolling-demo:v2 lifecycle:preStop:exec:command:["/bin/sh","-c","sleep 15"]

同时,在 Spring Boot 中启用优雅关闭:

# application.ymlserver:shutdown: graceful spring:lifecycle:timeout-per-shutdown-phase: 30s 

这样,当 Pod 被删除时:

  1. K8s 先从 Service Endpoints 中移除该 Pod(不再接收新请求);
  2. 执行 preStop hook(等待 15 秒,让现有请求完成);
  3. 发送 SIGTERM 信号给 Java 进程;
  4. Spring Boot 优雅关闭;
  5. 若超时未退出,发送 SIGKILL。
🌐 更多关于优雅关闭的内容,可参考 Kubernetes 官方文档 - Termination of Pods

4. 监控滚动更新指标

通过 Prometheus 监控以下指标:

  • kube_deployment_status_replicas_updated:已更新的副本数;
  • kube_pod_status_ready:Pod 就绪状态;
  • 应用层指标:错误率、延迟、吞吐量。

一旦异常,立即告警或自动回滚。


滚动更新 vs 其他部署策略

Kubernetes 还支持其他部署策略,适用于不同场景:

策略特点适用场景
RollingUpdate逐步替换,零停机大多数生产环境
Recreate先删所有旧 Pod,再建新 Pod可接受短暂停机,或有状态应用需完全重置
Blue/GreenK8s 原生不支持,需 Service 切换需要快速回滚、全量验证
CanaryK8s 原生不支持,需 Ingress 或 Service Mesh渐进式发布,小流量验证
💡 对于 Java 应用,RollingUpdate 是最常用且最安全的选择

常见问题与排查

Q1: 更新卡住了,怎么办?

  • 检查新 Pod 是否就绪:kubectl describe pod <new-pod>
  • 查看日志:kubectl logs <new-pod>
  • 检查 readinessProbe 是否失败;
  • 确认镜像是否拉取成功(网络、权限问题)。

Q2: 用户偶尔收到 502 错误?

  • 可能是旧 Pod 被终止时仍有请求在处理;
  • 解决方案:配置 preStop hook + 优雅关闭;
  • 确保 Service 的 sessionAffinity 未开启(除非必要)。

Q3: 如何暂停/恢复滚动更新?

# 暂停 kubectl rollout pause deployment/java-rolling-demo # 恢复 kubectl rollout resume deployment/java-rolling-demo 

适用于调试或分阶段更新。


总结

滚动更新是 Kubernetes 为 Java 应用提供的强大部署能力,它通过渐进式替换 Pod,结合就绪探针优雅关闭机制,实现了零停机、高可用的持续交付。

要成功实施滚动更新,你需要:

  1. 构建健康的 Java 应用:提供准确的 /actuator/health 端点;
  2. 合理配置 Deployment:设置 maxUnavailablemaxSurge、探针参数;
  3. 实现优雅关闭:使用 preStop hook 和 Spring Boot 的 graceful shutdown;
  4. 监控与回滚:建立可观测性,准备快速回滚方案。

随着云原生生态的成熟,滚动更新已成为 Java 应用上线的标准姿势。掌握它,你就能在微服务时代游刃有余地交付高质量软件 🎯。

🌟 最后提醒:永远在非生产环境充分测试你的滚动更新流程!自动化、标准化、可重复,是 DevOps 的核心精神。

Happy Coding & Happy Deploying! 🚀


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Read more

Xilinx FPGA温度等级及选型建议

Xilinx FPGA温度等级及选型建议

Xilinx(现为AMD的一部分)FPGA的温度等级决定了芯片可以在什么环境温度下可靠工作。其温度等级主要用型号后缀的一个字母表示,例如2FGG484C。以下是Xilinx FPGA主要的温度等级详解,从最常见到最严苛: 一、温度等级 1. 商业级 (Commercial) - 后缀 C * 结温范围: 0°C 至 +85°C * 描述: 这是最常用、成本最低的等级。适用于绝大多数室内电子设备,如消费电子、网络设备、工业控制(环境可控)、实验室仪器、开发板等。 * 常见场景: 电脑、显示器、路由器、空调控制器、大学实验室的开发板(如Nexys, Arty, Basys系列)。 2. 工业级 (Industrial) - 后缀 I * 结温范围: -40°C

By Ne0inhk
比肩英伟达Jetson Orin NX-国产机器人大脑RDK-S100评测

比肩英伟达Jetson Orin NX-国产机器人大脑RDK-S100评测

提起机器人开发平台,目前行业内较为流行的当属英伟达的Jetson Orin 和高通的RB5。凭借英伟达成熟的GPU技术,以及高通在手机SoC领域积累的高性能优势,二者能够较为顺畅地将既有技术栈迁移至机器人平台。然而,这些企业均来自国外。那么,国内是否也有同样出色的机器人平台呢?答案是肯定的——这正是本文将要为大家介绍的地瓜机器人RDK-S100。 地瓜机器人源自以自动驾驶SoC闻名业界的地平线机器人,目前专注于机器人相关领域的研发。近年来,公司已陆续推出X3、X5等芯片组平台,并实现大规模量产。而此次介绍的S100芯片组,则是其最新一代产品,对应地平线J6平台。与英伟达Orin Nano模组及高通RB5模组类似,S100芯片组同样采用SIP模组形式供货,集成有S100主控芯片、DDR内存及PMIC等关键部件。而RDK-S100,正是基于该SIP模组打造的官方评估板。 本文将从硬件,软件两个方面,大致介绍一下RDK-S100。 硬件介绍 开发板的外包装,正面是开发板的名称,背面的文字说明了开发板硬件的配置。 包装内包含开发板一个(SIP模组和散热器已经安装上去),电源一个

By Ne0inhk

Stable Diffusion:AI人工智能图像生成的变革者

Stable Diffusion:AI人工智能图像生成的变革者 关键词:Stable Diffusion,AI图像生成,扩散模型,深度学习,图像合成 摘要:本文深入探讨了Stable Diffusion在AI人工智能图像生成领域的变革性作用。从其背景知识入手,详细阐述了核心概念、算法原理、数学模型,通过项目实战展示其具体应用,分析了实际应用场景,并推荐了相关的工具和资源。最后对Stable Diffusion的未来发展趋势与挑战进行总结,同时解答了常见问题,为读者全面了解这一前沿技术提供了系统的知识体系。 1. 背景介绍 1.1 目的和范围 随着人工智能技术的飞速发展,图像生成领域取得了显著的进展。Stable Diffusion作为其中的佼佼者,引发了广泛的关注。本文的目的在于全面介绍Stable Diffusion的原理、应用和发展前景,帮助读者深入理解这一技术。范围涵盖了从基础概念到实际应用的各个方面,包括算法原理、数学模型、项目实战以及未来趋势等。 1.2 预期读者 本文预期读者包括对人工智能、图像生成技术感兴趣的科研人员、开发者、学生以及相关行业的从业者。无论

By Ne0inhk
什么是GIM、EIM,和BIM、数字孪生有什么关系?用Revit二开还是通过游戏引擎或低代码开发?

什么是GIM、EIM,和BIM、数字孪生有什么关系?用Revit二开还是通过游戏引擎或低代码开发?

随着“碳中和”目标的全球推进,能源行业的数字化转型已成为必然趋势。 对能源、电力企业而言,利用数字化手段实现精准规划、高效建设、智慧运维与碳排放监管,迫在眉睫。 能源数字孪生大屏案例 在数字化浪潮中,BIM(建筑信息模型) 大家已不陌生。 但深入电力、能源领域,你可能还会频繁听到 GIM、EIM 这些词,它们和BIM是什么关系?最近大热的 “数字孪生” 又和它们有何关联? 一、什么是BIM、GIM、EIM、数字孪生? 简单来说,这几项技术都是为了用数字化的方式,更好地“描述”和“管理”我们现实中的物理世界(如建筑、工厂、电网),但它们的侧重点和应用领域有所不同。 1. BIM(建筑信息模型) 🔹名词解释 参考美国国家BIM标准NBIMS-US™的标准,BIM是一个数字化的过程。 它基于开放、可互操作的标准,

By Ne0inhk