前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >k8s容器的钩子与优雅停机

k8s容器的钩子与优雅停机

作者头像
SRE运维手记
发布2024-09-25 15:49:13
720
发布2024-09-25 15:49:13
举报
文章被收录于专栏:SRE运维手记

01、背 景

在 Kubernetes 中,每次微服务的代码发布都意味着创建新版本的 pod 并删除旧 pod,如果部署不够优雅的话,可能出现如下两个问题:

1. 正在处理请求的pod被删除,在请求没有做幂等处理的情况下,就会出现数据重复、数据错误,亦或导致分布式系统数据不一致;

2. Kubernetes 将流量路由到已被删除的 pod,导致处理请求失败造成用户体验不佳。

所以,为了让代码发布的部署过程不影响业务的正常运行和用户无感知,我们需要实现容器的优雅停机。

02、容器的生命周期钩子

在介绍优雅停机之前,我们先来了解下k8s的容器都有哪些生命周期钩子?作用是什么?要怎么使用?

Kubernetes的容器有两种生命周期钩子(Lifecycle Hooks):

PostStart

这个钩子会在容器被创建后立即执行,但无法保证会在容器的起始点 ENTRYPOINT之前执行,如果执行时间太长,将会阻止Pod状态进入running,可用于数据初始化、容器启动回调等场景。如果需要保证在应用程序启动前就要执行完的任务,可以考虑放在初始化容器( Init Containers)中去实现。

PreStop

这个钩子会在容器被结束前执行,执行期间Pod状态为 Terminating,运行时间受终止宽限期( terminationGracePeriodSeconds)约束,超出宽限期Pod将被强制杀死,可用于容器回收前的数据清理、优雅停机等场景。

上述的两个钩子(PostStart 和 PreStop)都有四种类型,分别为:exec、httpGet、tcpSocket 和 sleep。由于这四种钩子类型在 PostStart 和 PreStop 中的使用方法一致,下面以 PreStop 为例介绍这四种钩子类型的使用方法:

  • exec(执行shell指令,可以是指令或shell脚本, 退出状态码为 0则为成功)
代码语言:javascript
复制
# shell指令模式
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "echo 'Container is stopping'"]

# shell脚本模式
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "/data/scripts/preStop.sh"]
  • httpGet(执行http get请求,响应状态码在[200,400)区间则为成功)
代码语言:javascript
复制
lifecycle:
  preStop:
    httpGet:
      path: /shutdown  # 请求的uri
      port: 8080       # 端口
      host: api.yilingyi.com  # 主机域名,不加该字段将请求Pod本身
      scheme: HTTP     # http协议,默认值HTTP,支持HTTP、HTTPS
  • tcpSocket(执行tcp socket请求, TCP连接成功建立则为成功)
代码语言:javascript
复制
lifecycle:
  preStop:
    tcpSocket:
      port: 8080
  • sleep(将容器暂停5秒,Kubernetes 1.30的新特性 PodLifecycleSleepAction,待验证)
代码语言:javascript
复制
lifecycle:
  preStop:
    sleep:
      seconds: 5

请注意,如果 PostStart 或 PreStop 回调失败,容器将被杀死,所以回调处理的程序应尽量轻量级及把控好执行的时间。

03、微服务优雅停机实现

本文将以k8s + SpringBoot + Nacos作为案例,介绍在实际业务场景中如何实现微服务的优雅停机,从而实现代码发布时的零宕机。

首先,先看看pod的默认删除过程:

1. Kube-apiserver接收到pod的删除请求,在Etcd上更新pod的状态为Terminating;

2. Kubelet 清理节点上容器相关的资源,如存储、网络;

3. Kubelet向容器发送SIGTERM,如果容器内进程没有任何配置,则容器立即退出。

4. 如果容器在默认的 30 秒内没有退出,Kubelet 将发送 SIGKILL 并强制其退出。

可以看出,在没有配置优雅停机之前,pod的删除相当暴力,所以为了更加优雅,我们加入了preStop hook,和将终止宽限期延长,具体实现如下:

1. preStop hook做了两件事情:

1)nacos反注册(也称 实例注销),确保在实例关闭期间不会再有新的请求被路由到该实例。

2) sleep 35s,nacos客户端的实例缓存为30s,30s后会重新拉取实例信息,超时为10s,一般不用10s这么长,所以我们设置为35s。

2. springboot开启优雅停机后,最大等待时间为30s。

3. terminationGracePeriodSeconds默认为30s,远小于preStop和springboot的时间之和,所以我们需要将其调大,我这里设置的是60s。

4. 其实在terminationGracePeriodSeconds耗尽后,k8s还给了一个2s的额外宽限期,最后才执行SIGKILL。

有了方案之后,接下来就是怎么执行落地了,请继续往下看。

04、操作步骤

  • 在SpringBoot > 2.3.0的版本后支持应用程序优雅停机,需要在java微服务的配置中设置如下两个属性,这一步很重要!!!
代码语言:javascript
复制
server:
  # 默认值immediate:即立即关闭,graceful:即优雅停机
  shutdown: graceful
spring:
  lifecycle:
    # 优雅停机最大等待时间,默认30s
    timeout-per-shutdown-phase: 30s
  • 接着是在微服务的yaml文件加上优雅停机的配置:

通过env定义POD_IP获取当前Pod的ip,传递给preStop进行nacos反注册。

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: sre-yilingyi
spec:
  containers:
  - name: sre-yilingyi
    image: 'sre/yilingyi:1.0.0'
    env:
      - name: POD_IP
        valueFrom:
          fieldRef:
            apiVersion: v1
            fieldPath: status.podIP
    lifecycle:
      preStop:
        exec:
          command:
            - /bin/sh
            - '-c'
            - >
              curl -s --connect-timeout 10 -m 20 -X POST "http://nacos.yilingyi.com:8848/nacos/v1/ns/instance?port=8080&healthy=true&ip=${POD_IP}&weight=1&enabled=false&serviceName=sre-yilingyi&encoding=GBK&namespaceId=production" && sleep 35
  terminationGracePeriodSeconds: 60

至此,完成微服务的优雅停机配置。

05、结 语

在流量敏感的业务场景中,微服务的优雅停机是必不可少的。虽然由于业务模式的不同,具体方案可能不能完全照搬,但希望上述内容能够为大家提供帮助和灵感。本期分享就到这里,谢谢!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SRE运维手记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档