Kubernetes 中如何优雅的停服

856 阅读2分钟

Graceful Shutdown

在负责实际生产中的敏感性业务时,我们经常会发现在发布或者底层基础设施异常时,业务会在短暂的时间内出现不可访问,虽然 Kubernetes 架构可以帮助我们很快的进行自动化修复,但是依然会存在一定时间的 downtime,本篇文章来介绍下如何对 Kubernetes 中的业务进行优雅停服。

当我们输入 kubectl delete pod 时,对应的 pod 会被删除掉,同时 endpoint controller 会从 Service 和 etcd 中移除它的 IP 地址和端口。

此时,我们可以通过 kubectl describe service 来观测整个过程。

describe svc

但就这还不够。

k8s 中存在多个组件去同步本地的 endpoints 列表

  • kube-proxy 会保存本地的 endpoints 列表去写入 iptables 规则
  • CoreDNS 使用 endpoint 列表去重新配置 DNS entries

例如 Ingress 控制器,Istio 等也是如此同步的。

其他控制器对 endpoint 的依赖

所有这些组件都将(最终)删除之前的端点,这样就不会有流量再次到达它。

同时,kubelet 也会收到更改通知并删除 pod。

那么当 kubelet 在其他组件之前删除 pod 时会发生什么呢?

不幸的是,此时你的业务会经历一段时间的 downtime ,因为诸如 kube-proxy,CoreDNS,Ingress 控制器等组件会仍然使用该 IP 地址来路由流量。

所以,我们应该如何去处理此类情况,尽可能的减少我们业务的 downtime 时间呢?

如果在删除 pod 之前等待足够长的时间,传输中的流量仍然可以解决,并且新的流量可以分配给其他 pod。

所以,我们应该通过何种方式来在删除 pod 之前等待一段时间呢?

wait for delete

当 kubelet 删除 一个 pod 时,它将经历以下步骤:

  • 触发 preStop hook (如果有的话)
  • 发送 SIGTERM 信号
  • 发送 SIGKILL 信号 (after 30 seconds)

优雅停机三大步

因此,我们可以使用 preStop 钩子来拆入人为的延迟

preStop 配置

也可以在应用程序中接受 SIGTERM 信号并等待

此外,您可以优雅地停止该过程,并在完成等待后退出。

Kubernetes 默认给我们设置了 30s 来做相关的事情。

SIGTERM信号处理

那我们应该等待多久呢?10s,20s 还是 30s 呢?其实没有一个标准的答案。

虽然 endpoints 的同步只需要花费很短的时间,但是 Kubernetes 不能保证任何时间,也不能保证所有组件都能同时完成。

delete pod 流程

相关链接: