• Pod 一直处于 Pending 状态
    • 节点资源不够
    • 不满足 nodeSelector 与 affinity
    • Node 存在 Pod 没有容忍的污点
      • 手动添加的污点
      • 自动添加的污点
    • 低版本 kube-scheduler 的 bug
    • kube-scheduler 没有正常运行
    • 驱逐后其它可用节点与当前节点有状态应用不在同一个可用区

    Pod 一直处于 Pending 状态

    Pending 状态说明 Pod 还没有被调度到某个节点上,需要看下 Pod 事件进一步判断原因,比如:

    1. $ kubectl describe pod tikv-0
    2. ...
    3. Events:
    4. Type Reason Age From Message
    5. ---- ------ ---- ---- -------
    6. 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.

    下面列举下可能原因和解决方法。

    节点资源不够

    节点资源不够有以下几种情况:

    • CPU 负载过高
    • 剩余可以被分配的内存不够
    • 剩余可用 GPU 数量不够 (通常在机器学习场景,GPU 集群环境)

    如果判断某个 Node 资源是否足够? 通过 kubectl describe node <node-name> 查看 node 资源情况,关注以下信息:

    • Allocatable: 表示此节点能够申请的资源总和
    • Allocated resources: 表示此节点已分配的资源 (Allocatable 减去节点上所有 Pod 总的 Request)

    前者与后者相减,可得出剩余可申请的资源。如果这个值小于 Pod 的 request,就不满足 Pod 的资源要求,Scheduler 在 Predicates (预选) 阶段就会剔除掉这个 Node,也就不会调度上去。

    不满足 nodeSelector 与 affinity

    如果 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 解析失败,使得业务中断。

    Node 存在 Pod 没有容忍的污点

    如果节点上存在污点 (Taints),而 Pod 没有响应的容忍 (Tolerations),Pod 也将不会调度上去。通过 describe node 可以看下 Node 有哪些 Taints:

    1. $ kubectl describe nodes host1
    2. ...
    3. Taints: special=true:NoSchedule
    4. ...

    污点既可以是手动添加也可以是被自动添加,下面来深入分析一下。

    手动添加的污点

    通过类似以下方式可以给节点添加污点:

    1. $ kubectl taint node host1 special=true:NoSchedule
    2. node "host1" tainted

    另外,有些场景下希望新加的节点默认不调度 Pod,直到调整完节点上某些配置才允许调度,就给新加的节点都加上 node.kubernetes.io/unschedulable 这个污点。

    自动添加的污点

    如果节点运行状态不正常,污点也可以被自动添加,从 v1.12 开始,TaintNodesByCondition 特性进入 Beta 默认开启,controller manager 会检查 Node 的 Condition,如果命中条件就自动为 Node 加上相应的污点,这些 Condition 与 Taints 的对应关系如下:

    1. Conditon Value Taints
    2. -------- ----- ------
    3. OutOfDisk True node.kubernetes.io/out-of-disk
    4. Ready False node.kubernetes.io/not-ready
    5. Ready Unknown node.kubernetes.io/unreachable
    6. MemoryPressure True node.kubernetes.io/memory-pressure
    7. PIDPressure True node.kubernetes.io/pid-pressure
    8. DiskPressure True node.kubernetes.io/disk-pressure
    9. 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 的 bug

    可能是低版本 kube-scheduler 的 bug, 可以升级下调度器版本。

    kube-scheduler 没有正常运行

    检查 maser 上的 kube-scheduler 是否运行正常,异常的话可以尝试重启临时恢复。

    驱逐后其它可用节点与当前节点有状态应用不在同一个可用区

    有时候服务部署成功运行过,但在某个时候节点突然挂了,此时就会触发驱逐,创建新的副本调度到其它节点上,对于已经挂载了磁盘的 Pod,它通常需要被调度到跟当前节点和磁盘在同一个可用区,如果集群中同一个可用区的节点不满足调度条件,即使其它可用区节点各种条件都满足,但不跟当前节点在同一个可用区,也是不会调度的。为什么需要限制挂载了磁盘的 Pod 不能漂移到其它可用区的节点?试想一下,云上的磁盘虽然可以被动态挂载到不同机器,但也只是相对同一个数据中心,通常不允许跨数据中心挂载磁盘设备,因为网络时延会极大的降低 IO 速率。