找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2378

积分

1

好友

331

主题
发表于 2025-12-30 16:05:55 | 查看: 20| 回复: 0

在 Kubernetes 集群运维中,Pod 处于 Pending 状态是常见的故障现象之一,往往意味着调度环节遇到了阻碍。究竟是什么原因导致调度器无法为 Pod 找到合适的归宿?本文将系统性地梳理 10 种导致 Pod Pending 的典型场景,并提供清晰的排查思路与解决方案。

什么是 Pending 状态

Pod 的 Pending 状态表明它已被 API Server 接收,但尚未被调度到任何节点上运行。这个阶段卡在了 kube-scheduler 的调度逻辑中,任何导致调度器无法找到合适节点的因素都会使 Pod 停留在此状态。理解调度器的运作机制,是快速定位问题的关键。

环境信息

本文的排查命令和配置基于以下典型生产环境:

  • Kubernetes 版本:1.28.x
  • 容器运行时:containerd 1.7.x
  • 集群规模:50+ 节点,3000+ Pod

调度失败的 10 种场景与排查思路

场景一:资源不足(最常见)

这是最普遍的 Pending 原因。集群节点的 CPU 或内存资源无法满足 Pod 的 requests 配置要求。

典型症状
执行 kubectl describe pod my-pod -n my-namespace,在 Events 中会看到类似信息:

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  30s   default-scheduler  0/10 nodes are available:
          10 Insufficient cpu, 10 Insufficient memory.

排查步骤

# 查看集群整体资源使用情况
kubectl top nodes

# 查看节点可分配资源概览
kubectl describe nodes | grep -A 5 "Allocated resources"

# 查看具体节点的资源详情
kubectl describe node node-1 | grep -A 20 "Allocated resources"

真实案例与解决
一个 Java 应用的 Deployment 设置了 requests.memory: 4Gi,新建 Pod 全部 Pending。排查发现集群总内存充足,但所有节点的可用内存都被大量小容器碎片化,没有单个节点能提供连续的 4Gi 空间。

  • 临时方案:清理一些可驱逐的低优先级 Pod。
  • 长期方案:调整节点规格或优化应用内存申请。

资源配置建议

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:latest
    resources:
      requests:
        memory: "256Mi" # 初始值不宜过大,为调整留有余地
        cpu: "100m"
      limits:
        memory: "512Mi"
        cpu: "500m"

场景二:节点 Taint 与 Pod Toleration 不匹配

节点被打上了污点(Taint),而 Pod 没有配置对应的容忍(Toleration)。

排查命令

# 查看所有节点的 Taint
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

# 查看特定节点的 Taint 详情
kubectl describe node node-1 | grep -A 5 Taints

常见的系统 Taint

node.kubernetes.io/not-ready:NoSchedule          # 节点未就绪
node.kubernetes.io/unreachable:NoSchedule        # 节点不可达
node.kubernetes.io/memory-pressure:NoSchedule    # 内存压力
node.kubernetes.io/disk-pressure:NoSchedule      # 磁盘压力
node.kubernetes.io/pid-pressure:NoSchedule       # PID 压力
node.kubernetes.io/network-unavailable:NoSchedule # 网络不可用

踩坑记录与解决
曾为 GPU 节点设置自定义 Taint:nvidia.com/gpu=true:NoSchedule,但新增 GPU 节点时忘记打上此标签,导致普通业务 Pod 被调度上去,浪费了昂贵的 GPU 资源。后来通过 Admission Webhook 强制校验。
解决方案是为需要调度到特定节点的 Pod 配置对应的 Toleration:

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
  - name: gpu-app
    image: gpu-app:latest
  tolerations:
  - key: "nvidia.com/gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

场景三:NodeSelector 或 NodeAffinity 无法满足

Pod 通过 nodeSelectornodeAffinity 指定了节点标签选择条件,但集群中没有节点满足条件。

排查命令

# 查看 Pod 的 nodeSelector 配置
kubectl get pod my-pod -o jsonpath='{.spec.nodeSelector}'

# 查看所有节点的标签
kubectl get nodes --show-labels

# 查找带有特定标签的节点
kubectl get nodes -l disktype=ssd

Events 中的典型报错

Warning  FailedScheduling  10s   default-scheduler  0/10 nodes are available:
         10 node(s) didn‘t match Pod’s node affinity/selector.

真实案例与修复
日志收集 DaemonSet 配置了 nodeSelector: logging=enabled,新扩容的节点未打此标签,导致 DaemonSet Pod 无法调度。
快速修复命令:

# 为单个节点添加标签
kubectl label nodes node-new logging=enabled
# 批量为所有 worker 节点添加标签
kubectl label nodes -l node-role.kubernetes.io/worker= logging=enabled

场景四:PVC 未绑定或 StorageClass 问题

Pod 声明挂载的 PersistentVolumeClaim (PVC) 处于 Pending 状态,未被绑定到 PersistentVolume (PV),或 StorageClass 配置有误。

排查命令

# 查看 PVC 状态
kubectl get pvc -n my-namespace
# 查看 PVC 详情
kubectl describe pvc my-pvc -n my-namespace
# 查看 StorageClass 列表
kubectl get storageclass

PVC 处于 Pending 状态是直接线索。

踩坑记录
使用云厂商的 NAS 作为存储后端时,一旦存储配额用尽,CSI 驱动可能不会返回明确错误,仅表现为 PVC 持续 Pending,需通过云控制台查看配额告警才能定位。

排查 CSI 问题

# 查看 CSI  provisioner Pod 日志
kubectl logs -n kube-system csi-provisioner-xxx
# 查看 StorageClass 的 provisioner 配置
kubectl get storageclass standard -o yaml

场景五:Pod 优先级与抢占问题

低优先级 Pod 无法抢占高优先级 Pod 的资源,或集群未正确配置 PriorityClass。

查看集群 PriorityClass

kubectl get priorityclasses

输出示例:

NAME                      VALUE        GLOBAL-DEFAULT   AGE
system-cluster-critical   2000000000   false            100d
system-node-critical      2000001000   false            100d
high-priority             1000000      false            50d
low-priority              100          false            50d

配置示例

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "用于重要的业务服务"
---
apiVersion: v1
kind: Pod
metadata:
  name: important-pod
spec:
  priorityClassName: high-priority # 指定优先级
  containers:
  - name: app
    image: my-app:latest

重要注意事项
切勿滥用 system-cluster-criticalsystem-node-critical 这两个优先级,它们专为 kube-system 命名空间下的核心系统组件预留。误用可能导致关键系统组件(如 CoreDNS)被业务 Pod 抢占资源,引发集群级故障。

场景六:资源配额(ResourceQuota)限制

Namespace 配置的 ResourceQuota 资源配额已用尽,无法创建新的 Pod。

排查命令

# 查看 namespace 的配额使用情况
kubectl describe resourcequota -n my-namespace

典型输出会清晰展示已使用(Used)和上限(Hard):

Name:            compute-quota
Namespace:       my-namespace
Resource         Used    Hard
--------         ----    ----
limits.cpu       4       8
limits.memory    8Gi     16Gi
requests.cpu     2       4
requests.memory  4Gi     8Gi
pods             10      20

Events 报错示例

Error creating: pods “my-pod” is forbidden: exceeded quota: compute-quota,
requested: requests.memory=1Gi, used: requests.memory=4Gi, limited: requests.memory=4Gi

经验教训
为 Namespace 设置 ResourceQuota 后,务必配置对应的监控告警,当使用率超过阈值(如80%)时及时通知,避免在业务高峰或 HPA 自动扩容时因配额用尽导致服务中断。

场景七:LimitRange 默认值问题

Namespace 中配置的 LimitRange 为未设置资源请求/限制的 Pod 注入了较大的默认值,可能导致调度需求超过节点容量。

查看 LimitRange

kubectl describe limitrange -n my-namespace

典型问题配置

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: my-namespace
spec:
  limits:
  - default: # 默认 limits
      cpu: "2"
      memory: "4Gi"
    defaultRequest: # 默认 requests - 此值设置过大会导致调度困难
      cpu: "1"
      memory: "2Gi"
    type: Container

如果 Pod 未明确设置 resources.requests,将会被自动注入 requests.memory: 2Gi,这可能会使 Pod 因“内存不足”而无法调度。

场景八:Pod 反亲和性(Anti-Affinity)冲突

配置了硬性(requiredDuringSchedulingIgnoredDuringExecution)Pod 反亲和性,要求同一应用的多个副本不能调度到同一节点,但集群节点数量少于副本数。

典型配置与问题

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 5 # 期望5个副本
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: # 硬性要求
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - my-app
            topologyKey: kubernetes.io/hostname

如果集群只有3个节点,那么第4、5个 Pod 将因无法满足“不能调度到已有副本节点”的硬性规则而永远 Pending。

解决方案
将硬性反亲和性改为软性偏好(preferredDuringSchedulingIgnoredDuringExecution),并赋予权重,这样调度器会尽量满足,但不会因无法满足而彻底放弃调度。

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution: # 软性偏好
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - my-app
        topologyKey: kubernetes.io/hostname

场景九:节点处于 SchedulingDisabled 状态

节点因维护等原因被标记为“不可调度”(cordon)。

排查命令

# 查看节点状态,注意 STATUS 列
kubectl get nodes

输出示例中,Ready,SchedulingDisabled 表示节点就绪但已被禁止调度:

NAME     STATUS                     ROLES    AGE   VERSION
node-1   Ready                      worker   100d  v1.28.0
node-2   Ready,SchedulingDisabled   worker   100d  v1.28.0  # 被 cordon 了
node-3   Ready                      worker   100d  v1.28.0

恢复调度

kubectl uncordon node-2

运维建议:所有涉及节点调度的维护操作(如 cordon/drain)应遵循标准操作流程(SOP)并记录清单,确保操作完成后及时恢复(uncordon),避免遗忘。

场景十:调度器本身出问题(罕见但致命)

kube-scheduler 组件自身发生故障,例如 Pod 异常、领导选举失败等。

排查命令

# 查看 scheduler Pod 状态
kubectl get pods -n kube-system -l component=kube-scheduler
# 查看 scheduler 日志
kubectl logs -n kube-system kube-scheduler-master-1
# 检查调度器内部健康端点(如果可用)
kubectl get --raw /healthz/poststarthook/scheduling-queue

真实案例
自建集群中,主节点间 NTP 服务异常导致时钟偏差过大,进而引发 kube-scheduler 的 Leader 选举持续异常,表现为 Pod 调度出现随机延迟或 Pending。解决方案是修复时钟同步后重启 scheduler Pod。

通用排查流程

遇到 Pod Pending,建议按照以下系统化流程进行排查:

# 第一步:查看 Pod 详细状态和 Events(信息最全)
kubectl describe pod <pod-name> -n <namespace>

# 第二步:从 Events 中提取调度失败原因(FailedScheduling)

# 第三步:检查集群及节点资源状况
kubectl top nodes
kubectl describe nodes | grep -A 10 "Allocated resources"

# 第四步:检查节点状态与污点
kubectl get nodes
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

# 第五步:检查 PVC 状态(如果 Pod 使用了存储卷)
kubectl get pvc -n <namespace>

# 第六步:检查 ResourceQuota 和 LimitRange
kubectl describe resourcequota -n <namespace>
kubectl describe limitrange -n <namespace>

# 第七步:查看调度器组件日志
kubectl logs -n kube-system -l component=kube-scheduler --tail=100

预防措施与最佳实践

资源规划

为容器设置合理且留有余地的资源请求(requests)和限制(limits)。

resources:
  requests:
    cpu: "100m"    # 起步值,根据监控指标动态调整
    memory: "128Mi"
  limits:
    cpu: "500m"    # limits 通常设置为 requests 的 2-5 倍
    memory: "512Mi" # 避免设置过大,以防 OOMKilled 时影响范围过广

监控告警

配置告警规则,主动发现潜在问题。以下为 Prometheus 告警规则示例:

groups:
- name: k8s-scheduling
  rules:
  - alert: PodPendingTooLong
    expr: |
      kube_pod_status_phase{phase="Pending"} == 1
      and on(pod, namespace)
      (time() - kube_pod_created > 300)
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} Pending 超过 5 分钟"

  - alert: NodeResourcePressure
    expr: |
      sum by (node) (
        kube_pod_container_resource_requests{resource="memory"}
      ) / sum by (node) (
        kube_node_status_allocatable{resource="memory"}
      ) > 0.85
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "节点 {{ $labels.node }} 内存分配率超过 85%"

配额管理脚本

定期审计各命名空间的配额使用情况。

#!/bin/bash
# 检查所有 namespace 的配额使用情况
for ns in $(kubectl get ns -o jsonpath='{.items
  • .metadata.name}'); do   echo "=== Namespace: $ns ==="   kubectl describe resourcequota -n $ns 2>/dev/null || echo "No quota defined"   echo "" done
  • 故障排查速查表

    现象 可能原因 关键排查命令
    Insufficient cpu/memory 节点资源不足 kubectl top nodes
    node(s) didn't match selector 节点标签不匹配 kubectl get nodes --show-labels
    node(s) had taints Pod 不容忍节点污点 kubectl describe node \| grep Taint
    pod has unbound PVC PVC 未绑定 PV kubectl get pvc
    exceeded quota 命名空间资源配额用尽 kubectl describe resourcequota
    SchedulingDisabled 节点被 cordon kubectl get nodes
    pod anti-affinity Pod 反亲和性规则冲突 检查 Deployment 的 affinity 配置

    总结

    Pod Pending 问题的本质,是 kube-scheduler 无法为 Pod 找到满足所有约束条件的节点。排查过程犹如破案,需要根据线索(Events)逐一验证可能的原因。

    核心建议如下:

    1. 首要动作:养成第一时间查看 kubectl describe pod 输出中 Events 部分的习惯,绝大多数原因在此有直接或间接体现。
    2. 主动防御:建立涵盖资源水位、Pending Pod 时长、配额使用率等维度的监控告警体系,变被动救火为主动预防。
    3. 资源管理:结合业务实际监控数据,进行科学的容量规划与资源申请,为节点预留一定的缓冲资源。
    4. 配置审计:定期审计集群的节点标签(Label)、污点(Taint)、资源配额(ResourceQuota)等基础配置,确保其符合预期。

    许多棘手的故障,根源往往在于被忽视的基础配置。在云原生技术栈的实践中,保持对细节的关注和严谨的操作流程,是保障系统稳定性的基石。希望本文梳理的排查思路和案例,能帮助你更高效地解决 Kubernetes 调度难题。欢迎在云栈社区与更多同行交流运维实践。




    上一篇:C++虚函数表(vptr)内存布局与实现原理详解
    下一篇:大模型核心术语入门指南:LLM、RAG、Agent、vLLM与数据蒸馏详解
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-1-11 08:35 , Processed in 0.235554 second(s), 40 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2025 云栈社区.

    快速回复 返回顶部 返回列表