Skip to content

Kubernetes Pod 调度详解

Pod 是 Kubernetes 中最小的部署单元,而调度(Scheduling)决定了 Pod 被分配到哪个工作节点(Node)上运行。Kubernetes 调度器是一个控制平面组件,负责为新创建的未调度的 Pod 选择最优节点。本文将全面介绍 Pod 调度的核心概念、原理和配置方法。

调度器(kube-scheduler)

Kubernetes 默认调度器是 kube-scheduler,它以插件化、可扩展的方式工作。其主要职责是:

  • 监听 API Server 中 PodSpec.nodeName 为空的 Pod
  • 为每个待调度 Pod 按照调度算法选择一个最合适的节点
  • 将绑定(Binding)结果写回 API Server,完成调度

kube-scheduler 支持多调度器并存,你可以部署自定义调度器,并通过 spec.schedulerName 指定使用哪个调度器。

调度流程

调度过程分为两个阶段:过滤(Filtering)打分(Scoring),也称为"谓词"和"优先级"。

过滤阶段

过滤是所有节点的"海选"环节,只有通过所有过滤条件的节点才会进入下一阶段。常见过滤插件包括:

  • PodFitsResources:检查节点剩余资源(CPU、内存、扩展资源)是否满足 Pod 需求
  • PodFitsHostPorts:检查节点上要使用的 hostPort 是否已被占用
  • PodFitsHost:检查 Pod 的 spec.nodeName 是否匹配
  • CheckNodeSelector:检查 Pod 的 spec.nodeSelector 是否匹配节点标签
  • NodeAffinity:检查节点亲和性规则
  • PodToleratesNodeTaints:检查 Pod 的容忍度能否匹配节点的污点
  • CheckNodeUnschedulable:检查节点是否设置了 spec.unschedulable=true
  • MatchInterPodAffinity:检查 Pod 间亲和/反亲和规则

打分阶段

通过过滤的节点进入打分环节,每个评分插件给节点打一个分数(通常 0-100),最终选择总分最高的节点。若多个节点同分,调度器会从中随机选择一个以保证负载分布。常见打分插件包括:

  • NodeResourcesBalancedAllocation:优先资源使用更均衡的节点
  • NodeResourcesFit:优先资源分配后剩余资源更多的节点(LeastRequestedPriority)
  • ImageLocality:优先已有 Pod 所需镜像的节点
  • InterPodAffinity:根据 Pod 间亲和规则打分
  • TaintToleration:根据污点容忍规则打分

从 Kubernetes v1.15 开始,调度器引入了调度框架(Scheduling Framework),允许开发者通过扩展点(Extension Point)集成自定义调度逻辑。

基础节点选择方式

nodeName

最直接但通常不推荐的方式。直接在 Pod 定义中指定节点名称:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node-01 # 直接指定节点名
  containers:
    - name: nginx
      image: nginx

缺点:节点故障、资源不足等情况下无法自动迁移,且绑定失败会导致 Pod 一直 Pending。

nodeSelector

通过节点标签选择节点。首先给节点打标签:

bash
kubectl label nodes node-01 disktype=ssd

然后在 Pod 中指定 nodeSelector:

yaml
spec:
  nodeSelector:
    disktype: ssd

Pod 只能调度到带有 disktype=ssd 标签的节点上。

节点亲和性(Node Affinity)

节点亲和性是 nodeSelector 的增强版,支持更丰富的匹配逻辑(In、NotIn、Exists、DoesNotExist、Gt、Lt)和软约束(preferred)。

节点亲和性配置在 spec.affinity.nodeAffinity 下。

requiredDuringSchedulingIgnoredDuringExecution

硬约束:Pod 必须调度到满足规则的节点上,否则无法调度。

yaml
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/e2e-az-name
                operator: In
                values:
                  - e2e-az1
                  - e2e-az2

preferredDuringSchedulingIgnoredDuringExecution

软约束:调度器会尽量满足,但不强制。可以设置权重(weight,1-100)。

yaml
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoringDuringExecution:
        - weight: 50
          preference:
            matchExpressions:
              - key: another-node-label-key
                operator: In
                values:
                  - another-node-label-value

污点(Taint)与容忍(Toleration)

污点应用于节点,表示节点拒绝某些 Pod 运行;容忍应用于 Pod,表示 Pod 可以"容忍"节点的污点。两者配合可以实现"专用节点"、"排斥特定 Pod"等高级调度策略。

设置污点

bash
# 添加污点(key=value,效果为NoSchedule)
kubectl taint nodes node-01 key1=value1:NoSchedule

# 查看污点
kubectl describe nodes node-01 | grep Taints

# 移除污点
kubectl taint nodes node-01 key1=value1:NoSchedule-

污点效果有三种:

  • NoSchedule:不允许新 Pod 调度到此节点,已运行 Pod 不受影响
  • PreferNoSchedule:调度器尽量不调度到此节点,软版本
  • NoExecute:不允许新 Pod 调度,且节点上未容忍此污点的 Pod 将被驱逐

配置容忍

在 Pod 的 spec.tolerations 中配置:

yaml
spec:
  tolerations:
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"
      # tolerationSeconds: 3600   # 仅在 NoExecute 时有效

容忍也支持 Exists 操作符(忽略 value),以及空 key 匹配所有污点。

当节点有 NoExecute 污点时,Pod 必须添加相应容忍,否则会被驱逐。通过 tolerationSeconds 可以指定容忍的时间长度,超时后仍会被驱逐。

Pod 间亲和性(Pod Affinity)与反亲和性(Pod AntiAffinity)

根据已经运行在节点上的 Pod 的标签来决定调度位置。这对于服务就近部署(降低延迟)、分散部署(提高可用性)非常有用。

配置在 spec.affinity.podAffinityspec.affinity.podAntiAffinity 下。

拓扑域(topologyKey)

拓扑域指的是节点标签中代表某一"位置"的键,例如 kubernetes.io/hostname(节点)、topology.kubernetes.io/zone(可用区)、topology.kubernetes.io/region(地域)。

示例

yaml
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values:
                  - backend
          topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 100
          podAffinityTerm:
            labelSelector:
              matchExpressions:
                - key: app
                  operator: In
                  values:
                    - frontend
            topologyKey: topology.kubernetes.io/zone

解释:

  • 硬亲和:Pod 必须调度到有 app=backend 类型 Pod 的同一节点(hostname 拓扑域)
  • 软反亲和:尽量不让同一个可用区(zone)内出现两个 app=frontend 的 Pod,权重 100

优先级(Priority)与抢占(Preemption)

当集群资源不足时,可以通过 Pod 优先级和抢占机制,优先保证高优先级 Pod 运行。

PriorityClass

首先定义优先级类别:

yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000 # 数值越大优先级越高
globalDefault: false
description: "This priority class is for critical services."

在 Pod 中指定优先级

yaml
spec:
  priorityClassName: high-priority

抢占机制

当高优先级 Pod 无法找到合适节点调度时,调度器会尝试驱逐一些低优先级 Pod 以释放资源。抢占过程会遵循 PodDisruptionBudget(PDB)保障,被驱逐的 Pod 会进入失败状态,但会被其控制器重建(可能再次被抢占)。

注意:抢占可能导致服务中断,生产环境请谨慎使用,并设置合理的优先级差异。

指定调度器

Kubernetes 支持多调度器。你可以部署自定义调度器(例如基于 GPU、延迟、成本等),然后在 Pod 中指定:

yaml
spec:
  schedulerName: my-custom-scheduler

如果未指定,默认使用 default-scheduler

调度失败排查常用命令

bash
# 查看 Pod 调度失败原因
kubectl describe pod <pod-name>

# 查看节点资源与标签
kubectl describe node <node-name>

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

# 查看调度器日志(如果是自建集群)
kubectl logs -n kube-system kube-scheduler-control-plane

常见调度失败原因:

  • 0/3 nodes are available: 3 Insufficient cpu
  • 0/3 nodes are available: 1 node(s) had taint
  • 0/3 nodes are available: 1 node(s) didn't match pod affinity rules
  • 0/3 nodes are available: 2 node(s) didn't match node selector

总结

调度方式类型适用场景推荐程度
nodeName硬指定测试、调试不推荐生产
nodeSelector硬限制简单标签筛选较推荐
节点亲和(required)硬限制复杂标签筛选推荐
节点亲和(preferred)软偏好优选节点推荐
污点+容忍排斥/专用特殊节点、独占节点推荐
Pod 亲和(required)硬限制服务就近部署根据场景
Pod 反亲和(required)硬限制分散风险、高可用推荐重要服务
Pod 亲和/反亲和(preferred)软偏好优化性能/可靠性推荐
优先级+抢占保障资源关键业务保活谨慎使用
自定义调度器完全定制特殊资源/算法按需

理解 Pod 调度是 Kubernetes 运维和优化的核心能力。实际应用中建议优先采用 nodeSelector、节点亲和性和 Pod 反亲和性,并根据业务重要性合理使用污点/容忍与优先级机制。