k8s工作节点宕机后pod未及时调度问题
k8s工作节点宕机后pod未及时调度问题
一、问题描述
在k8s集群环境(v1.20.6)下,工作节点分布在不同服务器下,可能因为某些不可控因素,会导致主节点和工作节点kubelet服务心跳断开,工作节点上运行的pod无法对外提供服务;现发现工作节点宕机后,该工作节点上运行的pod未及时调度到其他可用工作节点,而是过了5分钟才将pod调度到其他工作节点,继续正常对外提供服务。对于这个现象,查阅kubernetes官方网站资料得知:
“如果节点 Ready 条件处于
Unknown或者False状态的时间超过了pod-eviction-timeout值, (一个传递给 kube-controller-manager 的参数), 节点上的所有 Pod 都会被节点控制器计划删除。默认的逐出超时时长为 5 分钟。 某些情况下,当节点不可达时,API 服务器不能和其上的 kubelet 通信。 删除 Pod 的决定不能传达给 kubelet,直到它重新建立和 API 服务器的连接为止。”
我们通过更改kube-controller-manager组件,加上--pod-eviction-timeout=20s启动参数,再次关闭其中一个工作节点的kubelet服务,在主节点发现工作节点已经变为NotReady服务,但是等待 20s 后还是发现该工作节点上运行pod并未调度到其他节点。
二、解决方案
v1.13之前版本k8s:
在v1.13版本之前
TaintBasedEvictions功能还未开启,此时工作节点状态为Not-Ready之后,controller-manager直接判断Not-Ready时间是否超过了--pod-eviction-timeout,超过就进行删除。1
kube-controller-manager组件,加上`--pod-eviction-timeout=20s`启动参数
v1.13及以后版本k8s:
v1.13及以后版本,
TaintBasedEvictions功能开启之后就不会使用了该参数,转而使用condition+taint方案。也就是说工作节点Not-Ready之后,pod的驱逐时间完全由每个pod toleration中 tolerationSecond决定,而不是由controller-manager的参数--pod-eviction-timeout统一决定。节点生命周期管理都是通过condition + taint的方式进行管理。其主要逻辑由三部分组成:
- 不断地检查所有node状态,设置对应的condition
- 不断地根据node condition 设置对应的taint
- 不断地根据taint驱逐node上面的pod
1
2
3
4
5
6
7
8
9
10# pod yaml配置清单中,默认的tolerations,300s后也就是5分钟后对Not-Ready节点上的pod进行驱逐,调度到其他节点
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300方案为更改tolerations中tolerationSeconds的时间
三、延伸扩展资料整理
1. 工作节点状况:
| 节点状况 | 描述 |
|---|---|
Ready |
如节点是健康的并已经准备好接收 Pod 则为 True;False 表示节点不健康而且不能接收 Pod;Unknown 表示节点控制器在最近 node-monitor-grace-period 期间(默认 40 秒)没有收到节点的消息 |
DiskPressure |
True 表示节点的空闲空间不足以用于添加新 Pod, 否则为 False |
MemoryPressure |
True 表示节点存在内存压力,即节点内存可用量低,否则为 False |
PIDPressure |
True 表示节点存在进程压力,即节点上进程过多;否则为 False |
NetworkUnavailable |
True 表示节点网络配置不正确;否则为 False |
- 节点污点
内置的污点包括(当节点状态变更为对应状态时,节点控制器会自动给节点添加一个污点。):
node.kubernetes.io/not-ready:节点未准备好。这相当于节点状态Ready的值为 “False“。node.kubernetes.io/unreachable:节点控制器访问不到节点. 这相当于节点状态Ready的值为 “Unknown“。node.kubernetes.io/out-of-disk:节点磁盘耗尽。node.kubernetes.io/memory-pressure:节点存在内存压力。node.kubernetes.io/disk-pressure:节点存在磁盘压力。node.kubernetes.io/network-unavailable:节点网络不可用。node.kubernetes.io/unschedulable: 节点不可调度。node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 启动时指定了一个 “外部” 云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。
- 污点属性字段
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项:
| effect | 描述 |
|---|---|
NoSchedule |
表示k8s将不会将Pod调度到具有该污点的Node上 (K8Snode添加这个effect类型污点,新的不能容忍的pod不能再调度过来,但是老的运行在node上不受影响) |
PreferNoSchedule |
表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去(pod会尝试将pod分配到该节点) |
NoExecute |
表示k8s将尽量避免将Pod调度到具有该污点的Node上 (K8Snode添加这个effect类型污点,新的不能容忍的pod不能调度过来,老的pod也会被驱逐) |
- 污点的驱逐
污点的 effect 值 NoExecute会影响已经在节点上运行的 Pod:
- 如果 Pod 不能忍受 effect 值为
NoExecute的污点,那么 Pod 将马上被驱逐 - 如果 Pod 能够忍受 effect 值为
NoExecute的污点,但是在容忍度定义中没有指定tolerationSeconds,则 Pod 还会一直在这个节点上运行。 - 如果 Pod 能够忍受 effect 值为
NoExecute的污点,而且指定了tolerationSeconds, 则 Pod 还能在这个节点上继续运行这个指定的时间长度。 - 如果未被过滤的污点中存在至少一个 effect 值为
NoSchedule的污点, 则 Kubernetes 不会将 Pod 分配到该节点。 - 如果未被过滤的污点中不存在 effect 值为
NoSchedule的污点, 但是存在 effect 值为PreferNoSchedule的污点, 则 Kubernetes 会 尝试 不将 Pod 分配到该节点。 - 如果未被过滤的污点中存在至少一个 effect 值为
NoExecute的污点, 则 Kubernetes 不会将 Pod 分配到该节点(如果 Pod 还未在节点上运行), 或者将 Pod 从该节点驱逐(如果 Pod 已经在节点上运行)。
- Pod容忍
设置了污点的 Node 将根据 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。但我们可以在 Pod 上设置容忍 ( Toleration ) ,意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上。
1 | # pod.spec.tolerations |
operator 的默认值是 Equal。
一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:
- 如果
operator是Exists(此时容忍度不能指定value),或者 - 如果
operator是Equal,则它们的value应该相等
说明:
存在两种特殊情况:
如果一个容忍度的
key为空且 operator 为Exists, 表示这个容忍度与任意的 key 、value 和 effect 都匹配,即这个容忍度能容忍任意 taint。如果
effect为空,则可以与所有键名key1的效果相匹配。
