关于java:Kubernetes之服务优雅升级

32次阅读

共计 1556 个字符,预计需要花费 4 分钟才能阅读完成。

前言

k8s自身就反对服务滚动降级,然而如果程序没有正确的解决退出信号时,就会导致局部申请间接被中断从而影响用户体验。

滚动降级步骤

每个 pod 代表一个集群中的节点,在 k8s 做 rolling-update 的时候默认会向旧的 pod 产生一个 SIGTERM 信号,如果利用没有对 SIGTERM 信号做解决的话,会立刻强制退出程序,这样的话会导致有些申请还没解决完,前端利用申请谬误。

先来回顾下 k8s 的滚动降级步骤:

  1. 启动一个新的 pod
  2. 期待新的 pod 进入 Ready 状态
  3. 创立 Endpoint,将新的 pod 纳入负载平衡
  4. 移除与老 pod 相干的 Endpoint,并且将老 pod 状态设置为 Terminating,此时将不会有新的申请达到老 pod
  5. 给老 pod 发送 SIGTERM 信号,并且期待 terminationGracePeriodSeconds 这么长的工夫。(默认为 30 秒)
  6. 超过 terminationGracePeriodSeconds 等待时间间接强制 kill 过程并敞开旧的 pod

这里要留神,SIGTERM 信号如果过程没有解决的话也其实也就会导致过程被强杀 ,如果解决了然而超过terminationGracePeriodSeconds 配置的工夫也一样会被强杀,所以这个工夫能够依据具体的状况去设置。

SpringBoot 解决 SIGTERM 信号

SpringBoot 中解决 SIGTERM 信号非常简单,只须要一个 @PreDestroy 注解就能够监听到:

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);
    }

    @PreDestroy
    public void shutdown() {System.out.println("shutdown")
    }
}

通过容器生命周期 hook 来优雅进行

在 pod 中容器将进行前,会执行 PreStop hook,hook 能够执行一个HTTP GET 申请或者 exec 命令,并且它们执行是阻塞的,能够利用这个个性来做优雅进行。

  • 调用HTTP GET

    "lifecycle": {
        "preStop": {
        "httpGet": {
                "path": "/shutdown",
                "port": 3000,
                "scheme": "HTTP"
            }
        }
    }
  • 调用exec

    "lifecycle": {
        "preStop": {
            "exec": {"command": ["/bin/sh", "-c", "sleep 30"]
            }
        }
    }

这样的益处是能够在 k8s 层面来解决优雅停机的问题,而不须要应用程序对 SIGTERM 信号做解决。

对于 PreStop 和 terminationGracePeriodSeconds

  1. 如果有 PreStop hook 会执行PreStop hook
  2. PreStop hook执行实现后会向 pod 发送 SIGTERM 信号。
  3. 如果在 terminationGracePeriodSeconds 工夫限度内,PreStop hook没有执行完的话,一样会间接发送 SIGTERM 信号,并且工夫缩短 2 秒。

即在有 PreStop hook 的状况下,也是在 terminationGracePeriodSeconds 工夫限度内,在超过这个工夫点之后,还会给出 2 秒过程解决 SIGTERM 信号的工夫,最初间接强杀。

以上状况曾经过 k8s 上验证过,参考:https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods

我是 MonkeyWie,欢送扫码???????? 关注!不定期在公众号中分享JAVAGolang 前端 dockerk8s 等干货常识。

正文完
 0