kubernetes之pod中断
目标读者:
-
想要构建高可用应用的应用所有者,因此需要知道pod会发生哪些类型的中断
-
想要执行自动化(比如升级和自动扩容)的集群管理员.
自愿和非自愿的中断
pod不会自动消息,除非有人(可能是一个人或者一个控制器)把它销毁了,或者出现无法避免的硬件或者系统软件错误.
我们把这些称作非自愿的不可避免的应用中断.
以下是示例:
-
用于支撑节点的机会出现硬件故障
-
集群管理员误操作把VM(实例)删除了
-
虚拟机故障导致VM实例消失
-
kernel panic
-
由于网络分区导致集群节点消失
-
由于资源耗尽导致pod被驱离
除了资源耗尽外,其它情况大部分读者应该都非常熟悉,它们并不是kubernetes特有的.
我们称其它的情况为自愿中断.这包括集群管理员或者应用拥有者采取的动作.应用拥有者采取的典型动作有:
-
删除了管理pod的deployment或者其它控制器
-
更新了deployment的pod模板导致重启
-
直接删除pod(比如误删除)
集群管理员的动作有如下:
-
排干node以便升级或修复
-
排干一个node以便对集群缩容
-
从节点中删除一个pod以便可以做其它的事情
这些动作可能由集群管理者直接触发,或者自动触发,或者有集群服务提供者触发
询问集群管理员或者云服务提供商或者查询文档来确定是否触发了自愿中止.如果以上都没有发生,你可以跳过创建Pod Disruption Budgets
注意:并非所有的自愿中断都被
Pod Disruption Budgets
约束,比如删除deployment或者pod会绕过Pod Disruption Budgets
处理中断
以下是一些可以减轻非自愿中断的办法
-
确保pod请求需要的资源
-
如果你想要高可用,制作程序副本集
-
如果想要更高可用性,使用跨区域集群部署应用
自愿中断的频率根据实际情况往往也是不同的.在一个基础的集群上,可能根本不会有自愿的中断.但是集群管理员或者服务提供商可能会运行一些额外的服务导致自愿中断.比如滚动更新可能会导致自愿中断.一些自动集群扩容为了防止完整节点碎片化也会自愿中断.集群管理员或者服务提供商应该用文档把可能导致的自愿中断写出来,以便查询.
kubernetes提供了这样一种特性,当高频率自愿中断发生时仍然能够保证集群的高可用性,我们称之为Disruption Budgets
Disruption Budgets
有些资料上翻译为中断预算,但是更多的是没有翻译,大家只要知道它的大致意思就行了,这里也不做翻译
Disruption Budgets如何工作
应用所有者可以为每个应用创建一个PodDisruptionBudget(PDB)
对象.PDB限制一个包含副本集的集群由于自愿中断而同时宕掉的pod的个数.例如,一个基于仲裁投票的应用想要保证运行的副本数永远不会低于某个数量以便仲裁.一个web前端想要保证运行中的副本数不会低于某一比例.
集群管理员和服务提供商应当通过遵守Pod Disruption Budgets
的Eviction API而不是直接删除pod或者deployment.例如可以使用kubectl drain
当集群管理员想通过kubectl drain
命令来排干一个节点.命令会尝试排干节点机器上的所有pod.驱离请求可能会暂时被拒绝,命令会周期性的重新发送失败请求直到所有pod都终止,或者达到了设定的超时时间.
PDB规定了副本集可以容忍的副本集的数量(实际上是能容忍的最小值),这是相对于它期望的数量而言的.比如一个有.spec.replicas: 5
的deployment希望在任何时候都有五个副本,如果PDB允许有4个副本运行,则Eviction API
允许同一时刻有一个副本中断,而不是2个.
期望的副本数量由pod控制器通过pod的.spec.replicas
计算得出,控制器通过.metadata.ownerReferences
被pod发现
PDB不能阻止非自愿的中断发生,但是它们会被计入预算
由于被删除或者更新导到不可用的pod也会计入预算,但是控制器(比如deployment,stateful-set)滚动更新时不会被PDB限制,滚动更新导致的失败会计入控制器的spec里
当一个pod通过eviction API被驱离,它会优雅的中止(请看podspec里的terminationGracePeriodSeconds
)
PDB示例
比如集群有从node-1到node-3这样的3个节点.集群中运行着一些应用,其中一个有三个副本,叫作pod-a,pod-b和pod-c.此外还有一个无关的,包含PDB的pod称作pod-x,它们的初始分布情况如下:
node-1 | node-2 | node-3 |
---|---|---|
pod-a available | pod-b available | pod-c available |
pod-x available |
同一副本集的三个节点是一个deployment的一部分,它们共享一个PDB,要求它们三个中至少有2个同时运行着.
假如集群管理员想要重启节点以便修复一个内核bug,集群管理员首先尝试通过kubectl drain
命令来排干node-1节点.命令会尝试把pod-a和pod-x驱离节点node-1.命令马上执行成功,上面的pod同时进入terminating
状态.现在集群处于如下状态:
node-1 draining | node-2 | node-3 |
---|---|---|
pod-a terminating | pod-b available | pod-c available |
pod-x terminating |
deployment发现其中一个节点终止了.因此它创建了一个替代节点叫作pod-d,由于node-1被封锁,因此它会落到其它节点.其它的控制器也会创建一个pod-y来替代pod-x
注意,对一StatefulSet,pod-a可能叫作pod-1,需要在被替代之前完全终止,它仍然叫作pod-a,但是PID可能不同了.除此之外(pod的名字的区别),这个例子也适用于StatefulSet.
现在集群处于如下状态:
node-1 draining | node-2 | node-3 |
---|---|---|
pod-a terminating | pod-b available | pod-c available |
pod-x terminating | pod-d starting | pod-y |
在某一个时间点,node-a上的节点被终止,现在集群的状态如下
node-1 drained | node-2 | node-3 |
---|---|---|
pod-b available | pod-c available | |
pod-d starting | pod-y |
此时,如果一个没有耐心的集群管理员尝试排干node-2或者node-3,排干命令会被阻止,因为只有两个可用的节点,它的PDB要求至少运行2个,过一段时间,pod-d变得可用
node-1 drained | node-2 | node-3 |
---|---|---|
pod-b available | pod-c available | |
pod-d available | pod-y |
此时,如果集群管理员尝试排干node-2,排干命令会以一定顺序驱离上面的两个pod,比如说先是pod-b然后是pod-d,它会成功驱离pod-b.但是当尝试驱离pod-d的时候会被拒绝,因为这会导致deployment只有一个可用pod
pod-b被驱离后并不会马上在其它节点上落地开始工作,也就是这个节点的替代节点并不能马上工作,此时如果再驱离pod-d会导致只有pod-c是可用的,因此会被拒绝.
deployment创建了一个pod-b的替代叫作pod-e,由于集群没有足够资源来调度pod-e因此此时drain会再入陷入阻塞.集群最终的状态如下:
node-1 drained | node-2 | node-3 | no node |
---|---|---|---|
pod-b available | pod-c available | pod-e pending | |
pod-d available | pod-y |
此时,集群管理员需要添加一个节点来让升级继续.
你可以看到基于以下原因,kubernetes怎样控制中断的速率:
-
集群需要多少个副本
-
优雅地中止一个实例需要多长时间
-
一个新的实例启动需要多长时间
-
控制器的类型
-
集群资源容量
分离集群拥有者和应用拥有者的角色
通常,把集群管理者和应用拥有者看作是对对方知之甚少不同的角色是有用的.这种职责分离在以下情形是有意义的:
-
多个开发团队使用同一个集群,这时候有一个中立的专家角色
-
当一些第三方工具或者服务被用来做集群的自动化管理工作.
怎样在集群中执行有中断性的动作
如果你是集群管理员,由于节点或者系统软件升级,你可能需要对集群的所有节点执行可能产生中断的动作,有以下选项:
-
升级过程中接受宕机时间
-
故障转移到一个完整的副本集群中.这能够保证没有宕机时间,但是可能需要花费高价钱来复制节点和花费人力来编排切换
-
使用能容忍中断的程序和使用PDB
-
没有宕机时间
-
最小量资源复制
-
允许更多的集群自动化管理
-
编写能容忍中断的程序是很有技巧的,但是容忍中断的工作很大部分是与支持自动扩容和容忍非自愿中断是重叠的
-