K8s + Springboot 如何实现 优雅停机 + 不停服更新

一、为什么要实现优雅停机 + 不停服更新?

  • 提升用户体验:避免服务中断,减少用户困扰;

  • 增强系统稳定性:确保服务在停止前处理完现有请求,减少错误,避免数据异常;

  • 支持持续交付:实现频繁部署而不影响业务连续性;

  • 降低成本:减少因服务中断带来的经济损失和维护成本;


二、如何实现优雅停机?

1、项目自身的配置:

其实,在Spring Boot 2.3 及以上版本中,已经内置了对优雅停机的支持,但是前提是确保我们服务中,已经已经正确引入了actuator依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

我们可以在 application.yml 或 application.properties 中进行如下配置:

server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

2、K8s中对的配置:

在 Kubernetes 中,我们需要确保 Pod 在停止之前有足够的时间来完成优雅停机,可对terminationGracePeriodSeconds参数进行如下配置:

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  terminationGracePeriodSeconds: 60  # 设置为合适的值,确保应用有足够的时间完成优雅停机
  containers:
  - name: example-container
    image: your-spring-boot-app:latest
    ports:
    - containerPort: 8080

3、对于没有内置优雅停机的程序,我们可以通过自定义优雅停机的端口,配合k8s的preStop钩子,完成优雅停机:

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  terminationGracePeriodSeconds: 60
  containers:
  - name: example-container
    image: your-spring-boot-app:latest
    ports:
    - containerPort: 8080
    lifecycle:
      preStop:
        exec:
          # command: ["sh", "-c", "sleep 10"]  # 预处理操作,例如等待 10 秒
          command: ["curl", "-XPOST", "127.0.0.1:50000/actuator/shutdown"]  # 调用优雅停机接口

4、进行了以上配置,我们的程序就可以实现优雅停机的效果了:

1731656063818307.png

调试期间,重点观察:pod是否是在 Graceful shutdown complete 成功打印后,才被删除的?

但是,光实现优雅停机,服务的高可用性还是没有得到完全保障的,我们好需要实现,服务的不停服更新才可以!


三、如何实现不停服更新?

不停服更新的关键点就在于:要实现 滚动更新 + 就绪/存活探针 的配置!

1、如何配置滚动更新:

对于滚动更新策略,正常时候我们使用k8s管理面板的页面操作会更方便一点,因为市面上,所有的面板都会提供这一块的配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-spring-boot-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1   # 也可以使用 25% 表示
      maxUnavailable: 0
  • maxSurge: "25%"  :在更新过程中最多可以创建当前副本数的 25% 的额外 Pod,从而加快更新速度。

  • maxUnavailable: 0  :确保在更新过程中没有 Pod 不可用,保持服务高可用性。

2、如何配置就绪/存活探针:

配置就绪/存活探针的关键就是,我们的系统有提供对应的探针,巧了,如果我们的 springboot 项目已经引入了actuator依赖,就是已经待了对应的探针的;

但是记得要把这两个探针加入登录认证的白名单哦!

之后,在k8s上配置时候,正常时候我们也会选择在k8s管理面板上进行配置:

1731657201951242.png

在滚动更新,且新pod未就绪的状态下,k8s会为此pod标记为特殊状态,并不会为其分配流量:

1731657530574686.png

当上述 “优雅停机 + 不停服更新”都进行了合理配置的情况下,我们应用程序的可靠性,将大大提升!

jiguiquan@163.com

文章作者信息...

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐