3. 调度策略核心概念:节点亲和性、Pod亲和性/反亲和性、污点与容忍度

在 Kubernetes 集群中,调度器(kube-scheduler)负责将 Pod 分配到合适的节点。默认的“轮询”或“资源余量”策略无法满足复杂生产环境的需求。本章深入解析三大核心调度原语:节点亲和性、Pod 亲和性/反亲和性以及污点与容忍度。理解这些概念是进行调度策略调优与配置漂移审计的基础。

3.1 节点亲和性(Node Affinity)

节点亲和性允许你根据节点上的标签(Label)来约束 Pod 可以调度到哪些节点。它替代了早期的 nodeSelector,提供了更丰富的匹配逻辑。

类型 语义 调度阶段 典型场景
requiredDuringSchedulingIgnoredDuringExecution 硬约束:必须满足规则,否则 Pod 无法调度 调度时 Pod 必须运行在具有 SSD 磁盘的节点上
preferredDuringSchedulingIgnoredDuringExecution 软约束:尽量满足规则,不满足时仍可调度到其他节点 调度时 Pod 优先调度到可用区 A,但可用区 B 也可接受
审计要点: 检查 requiredDuringScheduling 规则是否过于严格,导致节点故障时 Pod 无法重新调度。同时,注意 IgnoredDuringExecution 意味着节点标签在 Pod 运行后发生变化,不会影响已运行的 Pod,这是常见的配置漂移来源。

3.1.1 节点亲和性配置示例

apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 50
        preference:
          matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values:
            - us-east-1a
  containers:
  - name: nginx
    image: nginx:1.25

3.2 Pod 亲和性(Pod Affinity)与反亲和性(Pod Anti-Affinity)

Pod 亲和性/反亲和性基于已经在节点上运行的 Pod 的标签来决策调度,而非节点本身的标签。这对于微服务架构中的“就近部署”或“故障隔离”至关重要。

  • Pod 亲和性: 将 Pod 调度到与特定 Pod 相同的拓扑域(如节点、可用区)中。例如,将缓存服务和数据库服务调度到同一节点以减少网络延迟。
  • Pod 反亲和性: 将 Pod 调度到与特定 Pod 不同的拓扑域中。例如,将同一应用的不同副本分散到不同节点或可用区,以提高可用性。
属性 Pod 亲和性 Pod 反亲和性
拓扑键(topologyKey) 必须指定,用于定义“域”的范围 必须指定,用于定义“域”的范围
调度约束 required / preferred required / preferred
性能影响 较低,通常用于优化 较高,尤其是 required 规则,可能大幅限制调度
典型误用 忘记设置 topologyKey 导致调度范围过小 设置过于严格的反亲和性导致 Pod 无法调度
性能警告: 使用 requiredDuringScheduling 的 Pod 反亲和性时,如果集群中节点数量少于 Pod 副本数,会导致部分 Pod 一直处于 Pending 状态。审计时应关注此类配置是否与集群规模匹配。

3.2.1 Pod 反亲和性配置示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web
            topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx:1.25

3.3 污点(Taints)与容忍度(Tolerations)

污点与容忍度是一对“排斥-吸引”机制。污点标记在节点上,用于排斥不匹配的 Pod;容忍度标记在 Pod 上,允许 Pod 调度到具有特定污点的节点。

  • 污点效果(Effect):
    • NoSchedule:不调度新的 Pod 到该节点(除非有容忍度)。
    • PreferNoSchedule:尽量不调度,但不强制。
    • NoExecute:不仅不调度新 Pod,还会驱逐节点上已有的、没有对应容忍度的 Pod。
  • 容忍度操作符(Operator):
    • Equal:容忍度必须与污点的 key、value、effect 完全匹配。
    • Exists:只要污点的 key 和 effect 匹配即可,忽略 value。
审计与调优关联: 在 Prometheus 监控中,如果发现大量 Pod 处于 Pending 状态,应首先检查节点污点与 Pod 容忍度的匹配情况。配置漂移常表现为运维人员手动添加污点后,未同步更新相关 Pod 的容忍度。

3.3.1 污点与容忍度配置示例

# 给节点添加污点
# kubectl taint nodes node1 dedicated=gpu:NoSchedule

# Pod 容忍度配置
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"
  containers:
  - name: cuda-container
    image: nvidia/cuda:12.0-base

3.4 核心概念关系图

下图展示了调度器在决策时如何综合评估节点亲和性、Pod 亲和性/反亲和性以及污点与容忍度。调度器首先过滤掉不满足硬约束的节点,然后对剩余节点进行打分,最终选择最优节点。

调度策略核心概念关系图 调度策略核心概念关系图 待调度 Pod 阶段一:过滤(硬约束) 节点亲和性 (required) Pod 反亲和性 (required) 污点 (NoSchedule) 阶段二:打分(软约束) 节点亲和性 (preferred) Pod 亲和性 (preferred) 资源余量 / 优先级 绑定到最优节点

3.5 配置漂移审计对照表

在 Prometheus 驱动的审计体系中,以下配置项是漂移检测的重点。任何与基线不符的变更都应触发告警。

资源类型 审计字段 漂移风险 Prometheus 检测指标
Node spec.taints 手动添加/删除污点导致调度行为异常 kube_node_spec_taint{key="..."}
Pod / Deployment spec.affinity.nodeAffinity 节点标签变更后,Pod 仍被调度到不合适的节点 kube_pod_annotations{annotation="scheduler.alpha.kubernetes.io/node-selector"}
Pod / Deployment spec.tolerations 容忍度被移除或修改,导致 Pod 被驱逐 kube_pod_status_reason{reason="TaintToleration"}
Pod / Deployment spec.affinity.podAntiAffinity 反亲和性规则被放宽,导致 Pod 集中部署 kube_pod_affinity_term{type="podAntiAffinity"}
最佳实践: 建议将调度策略配置(亲和性、容忍度)作为 GitOps 的一部分进行版本管理。任何手动 kubectl taint 或 kubectl label 操作都应视为配置漂移事件,并触发审计流程。