排查 Pod 一直 Pending
Pod 一直 Pending 一般是调度失败,通常我们可以通过 describe 来看下 event 来判断 pending 原因:
$ kubectl describe pod tikv-0
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m (x106 over 33m) default-scheduler 0/4 nodes are available: 1 node(s) had no available volume zone, 2 Insufficient cpu, 3 Insufficient memory.
任何节点中都没有足够的资源来分配 pod
Kubernetes 会根据 Pod 的 Request 和所有节点的资源已分配与可分配的情况 (CPU, Memory, GPU, MaxPod 等) 来决定哪些节点可以被调度,如果所有节点都没有足够资源了,Pod 就会一直保持 Pending。
如果判断某个 Node 资源是否足够? 通过 kubectl describe node <node-name>
查看 node 资源情况,关注以下信息:
Allocatable
: 表示此节点能够申请的资源总和Allocated resources
: 表示此节点已分配的资源 (Allocatable 减去节点上所有 Pod 总的 Request)
前者与后者相减,可得出剩余可申请的资源。如果这个值小于 Pod 的 request,就不满足 Pod 的资源要求,Scheduler 在 Predicates (预选) 阶段就会剔除掉这个 Node,也就不会调度上去。
不满足亲和性
如果 Pod 包含 nodeSelector 指定了节点需要包含的 label,调度器将只会考虑将 Pod 调度到包含这些 label 的 Node 上,如果没有 Node 有这些 label 或者有这些 label 的 Node 其它条件不满足也将会无法调度。参考官方文档:https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
如果 Pod 包含 affinity(亲和性)的配置,调度器根据调度算法也可能算出没有满足条件的 Node,从而无法调度。affinity 有以下几类:
- nodeAffinity: 节点亲和性,可以看成是增强版的 nodeSelector,用于限制 Pod 只允许被调度到某一部分 Node。
- podAffinity: Pod 亲和性,用于将一些有关联的 Pod 调度到同一个地方,同一个地方可以是指同一个节点或同一个可用区的节点等。
- podAntiAffinity: Pod 反亲和性,用于避免将某一类 Pod 调度到同一个地方避免单点故障,比如将集群 DNS 服务的 Pod 副本都调度到不同节点,避免一个节点挂了造成整个集群 DNS 解析失败,使得业务中断。
节点不可调度
由于节点压力(NotReady)或人为行为(节点封锁),节点可能会变为不可调度的状态,这些节点在状态发生变化之前不会调度任何 pod。
可以通过 kubectl get node
查看节点是否是 NotReady
或 SchedulingDisabled
。
挂载磁盘或固定 IP 导致无法漂移
如果 Pod 挂载了磁盘(块存储),而一般云盘的实 现是不能跨可用区的(时延太高),如果集群中节点分布在多个可用区,当前可用区节点无资源可调度时,Pod 也无法漂移到其它可用区。
Pod 报类似如下事件日志:
0/4 nodes are available: 2 node(s) insufficient memory, 2 node(s) had no available volume zone.
解决方法:要么删除 pvc 并重建 pod,自动在被调度到的可用区里创建磁盘并挂载;要么在 pod 之前所在可用区内扩容节点以补充资源。
同理,如果固定了 IP(通过插件或云厂商的网络实现),通常 Pod 就不能漂移到其它子网的节点上去。
解决方法: 加节点,或取消固定 IP 然后重建。
污点与容忍
节点如果被打上了污点,Pod 必须要容忍污点才能调度上去:
0/5 nodes are available: 3 node(s) had taints that the pod didn't tolerate, 2 Insufficient memory.
通过 describe node 可以看下 Node 有哪些 Taints:
$ kubectl describe nodes host1
...
Taints: special=true:NoSchedule
...
如果希望 Pod 可以调度上去,通常解决方法有两个:
- 删除污点:
kubectl taint nodes host1 special-
- 给 Pod 加上这个污点的容忍:
tolerations:
- key: "special"
operator: "Equal"
value: "true"
effect: "NoSchedule"
我们通常使用后者的方法来解决。污点既可以是手动添加也可以是被自动添加,下面来深入分析一下。
手动添加的污点
通过类似以下方式可以给节点添加污点:
$ kubectl taint node host1 special=true:NoSchedule
node "host1" tainted
另外,有些场景下希望新加的节点默认不调度 Pod,直到调整完节点上某些配置才允许调度,就给新加的节点都加上 node.kubernetes.io/unschedulable
这个污点。
自动添加的污点
如果节点运行状态不正常,污点也可以被自动添加,从 v1.12 开始,TaintNodesByCondition
特性进入 Beta 默认开启,controller manager 会检查 Node 的 Condition,如果命中条件就自动为 Node 加上相应的污点,这些 Condition 与 Taints 的对应关系如下:
Conditon Value Taints
-------- ----- ------
OutOfDisk True node.kubernetes.io/out-of-disk
Ready False node.kubernetes.io/not-ready
Ready Unknown node.kubernetes.io/unreachable
MemoryPressure True node.kubernetes.io/memory-pressure
PIDPressure True node.kubernetes.io/pid-pressure
DiskPressure True node.kubernetes.io/disk-pressure
NetworkUnavailable True node.kubernetes.io/network-unavailable
解释下上面各种条件的意思:
- OutOfDisk 为 True 表示节点磁盘空间不够了
- Ready 为 False 表示节点不健康
- Ready 为 Unknown 表示节点失联,在
node-monitor-grace-period
这么长的时间内没有上报状态 controller-manager 就会将 Node 状态置为 Unknown (默认 40s) - MemoryPressure 为 True 表示节点内存压力大,实际可用内存很少
- PIDPressure 为 True 表示节点上运行了太多进程,PID 数量不够用了
- DiskPressure 为 True 表示节点上的磁盘可用空间太少了
- NetworkUnavailable 为 True 表示节点上的网络没有正确配置,无法跟其它 Pod 正常通信
另外,在云环境下,比如腾讯云 TKE,添加新节点会先给这个 Node 加上 node.cloudprovider.kubernetes.io/uninitialized
的污点,等 Node 初始化成功后才自动移除这个污点,避免 Pod 被调度到没初始化好的 Node 上。
kube-scheduler 没有正常运行
检查 maser 上的 kube-scheduler
是否运行正常,异常的话可以尝试重启临时恢复。