Files
kuboard-press/learning/k8s-intermediate/workload/disruption.md
2019-11-19 22:28:38 +08:00

12 KiB
Raw Blame History

vssueId, layout, description, meta
vssueId layout description meta
155 LearningLayout Kubernetes教程_本文面向想要构建高可用的应用程序的应用程序管理员_为此您需要理解有哪些毁坏_disruption_可能发生在Pod上_本文也是为集群管理员准备的_如果集群管理员想要将集群的部分管理任务自动化的话_例如_升级_自动伸缩等
name content
keywords Kubernetes教程,K8S教程,K8S培训,K8S Disruption,PodDisruptionBudget

容器组_毁坏Disruptions

参考文档: Disruptions

本文面向想要构建高可用的应用程序的应用程序管理员为此您需要理解有哪些毁坏disruption可能发生在Pod上。

本文也是为集群管理员准备的,如果集群管理员想要将集群的部分管理任务自动化的话,例如,升级、自动伸缩等。

::: tip Disruption ---> 毁坏。 暂时没想到合适的词,如果您有想法,请联系我。 :::

TOC

自愿的和非自愿的毁坏

除非有人人或者控制器销毁Pod或者出现不可避免的硬件/软件故障Pod不会凭空消失。此类不可避免的情况我们称之为非自愿的毁坏involuntary disruption。例如

  • 节点所在物理机的硬件故障
  • 集群管理员误删了虚拟机
  • 云供应商或管理程序故障导致虚拟机被删
  • Linux 内核故障
  • 集群所在的网络发生分片,导致节点不可用
  • 节点资源耗尽,导致 Pod 被驱逐

除了节点资源耗尽这种情况以外,大部分人对其他情况都十分熟悉,因为这并不是 Kubernetes 所特有的情况。

还有一类毁坏我们称之为自愿的毁坏voluntary disruptions。主要包括由应用管理员或集群管理员主动执行的操作。应用管理员可能执行的操作有

  • 删除 Deployment 或其他用于管理 Pod 的控制器
  • 修改 Deployment 中 Pod 模板的定义,导致 Pod 重启
  • 直接删除一个 Pod

集群管理员可能执行的操作有:

  • 排空节点 以便维修或升级
  • 排空节点,以将集群缩容
  • 从节点上删除某个 Pod以使得其他的 Pod 能够调度到该节点上

这些操作可能直接由集群管理员执行,或者由执行管理员运行的自动化脚本执行,也可能由您的集群托管商执行。

向您的集群管理员、云供应商询问,您的集群是否激活了任何形式的自愿的毁坏。如果没有激活,您无需创建 Pod Disruption Budgets。

::: danger 警告 并非所有自愿的毁坏都受 Pod Disruption Budgets 限制,例如,删除 Deployment 或 Pod。 :::

处理毁坏Disruptions

弥补非自愿的毁坏可以采取的方法有:

自愿的毁坏,发生频率不定。在一个基础的 Kubernetes 集群中,可能不会发生自愿的毁坏。当你的集群管理员或者托管供应商运行某些额外的服务是可能导致自愿的毁坏发生。例如:

  • 更新节点上的软件
  • 自定义实现的自动伸缩程序

集群管理员或托管供应商应该为您提供这方面的文档。

Kubernetes 提供了 Disruption Budget 这一特性,以帮助我们在高频次自愿的毁坏会发生的情况下,仍然运行高可用的应用程序。

Disruption Budget如何工作

应用程序管理员可以为每一个应用程序创建 PodDisruptionBudget 对象PDB。PDB限制了多副本应用程序在自愿的毁坏情况发生时最多有多少个副本可以同时停止。例如一个 web 前端的程序需要确保可用的副本数不低于总副本数的一定比例。

集群管理员以及托管供应商在进行系统维护时,应该使用兼容 PodDisruptionBudget 的工具(例如 kubectl drain,此类工具调用 Eviction API)而不是直接删除 Pod 或者 Deployment。

kubectl drain 命令会尝试将节点上所有的 Pod 驱逐掉。驱逐请求可能会临时被拒绝,kubectl drain 将周期性地重试失败的请求,直到节点上所有的 Pod 都以终止,或者直到超过了预先配置的超时时间。

PDB 指定了应用程序最少期望的副本数(相对于总副本数)。例如,某个 Deployment 的 .spec.replicas 为 5期望的副本数是 5个。如果他对应的 PDB 允许最低 4个副本数则 Eviction APIkubectl drain在同一时刻最多会允许1个自愿的毁坏而不是2个或更多

  • PDB 通过 Pod 的 .metadata.ownerReferences 查找到其对应的控制器Deployment、StatefulSet
  • PDB 通过 控制器Deployment、StatefulSet.spec.replicas 字段来确定期望的副本数
  • PDB 通过控制器Deployment、StatefulSet的 label selector 来确定哪些 Pod 属于同一个应用程序
  • PDB 不能阻止 非自愿的毁坏 发生,但是当这类毁坏发生时,将被计入到当前毁坏数里
  • 通过 kubectl drain 驱逐 Pod 时Pod 将被优雅地终止gracefully terminated参考 terminationGracePeriodSeconds

在滚动更新过程中被删除的 Pod 也将计入到 PDB 的当前毁坏数,但是控制器(例如 Deployment、StatefulSet在执行滚动更新时并不受 PDB 的约束。滚动更新过程中,同时可以删除的 Pod 数量在控制器对象Deployment、StatefulSet等的定义中规定参考滚动更新

PDB Example

假设有一个集群共有三个工作节点,node-1node-2node-3,集群上运行了多个应用程序,其中一个 Deployment 有 3个 Pod 副本 pod-apod-bpod-c,并且对应了 PDB 限定 3 个 Pod 中至少要有 2 个可用。另外有一个无关的 pod-x 没有对应的PDB。最开始时Pod 在节点上的分布如下表所示:

node-1 node-2 node-3
pod-a available pod-b available pod-c available
pod-x available

此时,假设集群管理员想要重启机器,以便更新 Linux 内核版本修复其中的一个漏洞。集群管理员首先尝试使用 kubectl drain 命令排空 node-1,此时 kubectl drain 将尝试驱逐 pod-apod-x。这个操作将立刻能够执行成功,两个 Pod 都将同时进入 terminating 状态,集群的状态将如下所示:

node-1 draining node-2 node-3
pod-a terminating pod-b available pod-c available
pod-x terminating

Deployment控制器发现其中的一个 Pod 正在终止,因此,将立刻创建一个新的 Pod 以替代该 Pod假设其为 pod-d。由于 node-1 已经被标记不可用cordoned 警戒线),pod-d 将调度到另外一个节点上。另外一个控制器同样也为 pod-x 创建了一个替代 Pod pod-y

此时,集群状态如下所示:

node-1 draining node-2 node-3
pod-a terminating pod-b available pod-c available
pod-x terminating pod-d starting pod-y

pod-apod-x 终止以后,集群状态如下所示:

node-1 drained node-2 node-3
pod-b available pod-c available
pod-d starting pod-y

此时,如果集群管理员不够耐心,立刻尝试排空 node-2node-3,则 kubectl drain 命令将被组织阻止,因为当前该 Deployment 只有 2个可用的 Pod而其 PDB 要求至少有 2个可用的 Pod。

pod-d 完成启动后,集群的状态将如下所示:

node-1 drained node-2 node-3
pod-b available pod-c available
pod-d available pod-y

此时,集群管理员尝试排空 node-2kubectl drain 将按照某种顺序尝试驱逐 node-2 上的两个 Pod假设先是 pod-b 然后是 pod-d。驱逐 pod-b 的操作将执行成功,但是,当 kubectl drain 尝试驱逐 pod-d 时,该请求将被拒绝,否则该 Deployment 将只剩下一个可用的 Pod。

Deployment 此时将创建一个 Pod pod-e 用于替换 Pod pod-b。由于集群中没有足够的资源来调度 pod-ekubectl 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中如下因素决定了毁坏发生的频率

  • 应用程序所需要的副本数
  • 对一个 Pod 执行优雅终止gracefully shutdown所需要的时间
  • 新的 Pod 实例启动所需要的时间
  • 控制器的类型
  • 集群资源的容量

区分集群管理员和应用管理员的角色

通常,我们认为集群管理员和应用管理员是不同的角色,且相互之间所共有的知识并不多。对这两个角色的职责进行区分,在如下场景中是非常有用的:

  • 多个应用程序团队共享一个 Kubernetes 集群
  • 第三方工具或服务将集群的管理自动化

Pod Disruption Budget 是区分两种角色时的必要的界面,双方要就此概念达成共识。如果你所在的组织中,并不严格区分集群管理员和应用程序管理员,则,您并不需要使用 Pod Disruption Budget。

如何执行毁坏性的操作Disruptive Action

如果您是集群管理员且需要在所有节点上执行毁坏性的操作disruptive action例如节点或系统软件的升级此时可能的选择有

  • 接受升级过程中的停机时间
  • 故障转移Failover到另外一个集群副本
    • 无停机时间,但是将有额外的代价,因为需要由双份的节点以及更多的人力成本来管理集群之间的切换
  • 编写容错的应用程序disruption tolerant application并使用 PDB
    • 无停机时间
    • 最少的资源冗余
    • 支持更多的集群管理自动化
    • 编写容错的应用程序disruption-tolerant application非常需要技巧但是要容忍自愿的毁坏所做的工作与支持自动伸缩autoscaling与容忍非自愿的毁坏tolerating involuntary disruption所做的工作是大量重叠的