共计 1556 个字符,预计需要花费 4 分钟才能阅读完成。
前言
k8s
自身就反对服务滚动降级,然而如果程序没有正确的解决退出信号时,就会导致局部申请间接被中断从而影响用户体验。
滚动降级步骤
每个 pod
代表一个集群中的节点,在 k8s 做 rolling-update
的时候默认会向旧的 pod
产生一个 SIGTERM
信号,如果利用没有对 SIGTERM
信号做解决的话,会立刻强制退出程序,这样的话会导致有些申请还没解决完,前端利用申请谬误。
先来回顾下 k8s 的滚动降级步骤:
- 启动一个新的 pod
- 期待新的 pod 进入 Ready 状态
- 创立 Endpoint,将新的 pod 纳入负载平衡
- 移除与老 pod 相干的 Endpoint,并且将老 pod 状态设置为 Terminating,此时将不会有新的申请达到老 pod
- 给老 pod 发送 SIGTERM 信号,并且期待 terminationGracePeriodSeconds 这么长的工夫。(默认为 30 秒)
- 超过 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
- 如果有
PreStop hook
会执行PreStop hook
。 PreStop hook
执行实现后会向 pod 发送SIGTERM
信号。- 如果在
terminationGracePeriodSeconds
工夫限度内,PreStop hook
没有执行完的话,一样会间接发送SIGTERM
信号,并且工夫缩短 2 秒。
即在有 PreStop hook
的状况下,也是在 terminationGracePeriodSeconds
工夫限度内,在超过这个工夫点之后,还会给出 2 秒过程解决 SIGTERM
信号的工夫,最初间接强杀。
以上状况曾经过 k8s 上验证过,参考:https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods
我是 MonkeyWie,欢送扫码???????? 关注!不定期在公众号中分享
JAVA
、Golang
、前端
、docker
、k8s
等干货常识。