Kubernetes

K8s 高阶调度全解

·21 分钟阅读·8294 字

梳理K8s 高阶调度的核心概念、工作机制与运维实践

📋 目录

K8s 高阶调度全解

1. 前置:默认调度器基础流程

1.1. 调度整体链路

  1. Pod 未指定节点 → 进入调度队列
  2. 预选阶段(Filter):过滤掉不满足条件的节点,输出候选节点列表
  3. 打分阶段(Score):对候选节点打分,分数最高者胜出
  4. 绑定(Bind):将 Pod 与目标节点绑定,完成调度

1.2. 内置默认预选/打分规则(了解即可)

  • 预选:资源充足、端口不冲突、节点就绪、主机名匹配等
  • 打分:资源均衡分配、最少请求优先等 高阶调度本质就是自定义预选规则、自定义打分规则、增加调度约束。

2. 第一部分:节点亲和性 & Pod 亲和/反亲和(Affinity)

用于精准控制 Pod 调度到哪些节点、和哪些 Pod 共处/隔离,是最常用的高阶调度能力,分为三类:

  • 节点亲和 nodeAffinity:Pod ↔ 节点
  • Pod 亲和 podAffinity:Pod ↔ 其他 Pod(尽量放一起)
  • Pod 反亲和 podAntiAffinity:Pod ↔ 其他 Pod(尽量分开) 通用语法规则:
    两种策略类型:
  1. requiredDuringSchedulingIgnoredDuringExecution:硬约束(必须满足,不满足则调度失败)
  2. preferredDuringSchedulingIgnoredDuringExecution:软约束(尽量满足,不满足也可调度)
    后缀 IgnoredDuringExecution 含义:运行中不再校验规则,节点/标签变化不驱逐已运行 Pod。

2.1. 节点亲和 nodeAffinity

根据节点标签筛选节点,替代传统 nodeSelector,能力更强(支持多条件、逻辑运算、软硬约束)。

2.2. 1)nodeSelector(传统基础,对比参考)

仅支持简单标签匹配,无软硬区分:


spec:

  nodeSelector:

    node-role: app

2.3. 2)硬节点亲和(必须满足)

节点不匹配则 Pod 一直处于 Pending。


apiVersion: v1

kind: Pod

metadata:

  name: node-affinity-required

spec:

  affinity:

    nodeAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

        nodeSelectorTerms:

        # 多个 matchExpressions 之间:逻辑 OR

        - matchExpressions:

            # 单个表达式内:逻辑 AND

          - key: node-role

            operator: In  # 运算符:In / NotIn / Exists / DoesNotExist / Gt / Lt

            values: ["app", "web"]

          - key: node-arch

            operator: In

            values: ["amd64"]

常用运算符

  • In:标签值在列表中
  • NotIn:标签值不在列表中
  • Exists:节点存在该标签(忽略 value)
  • DoesNotExist:节点不存在该标签
  • Gt/Lt:数值大小比较(多用于版本、资源标签)

2.4. 3)软节点亲和(优先满足)

设置权重 weight(1~100),权重越高优先级越高;无合适节点则调度到其他节点。


spec:

  affinity:

    nodeAffinity:

      preferredDuringSchedulingIgnoredDuringExecution:

      - weight: 80

        preference:

          matchExpressions:

          - key: node-zone

            operator: In

            values: ["zone-a"]

      - weight: 50

        preference:

          matchExpressions:

          - key: node-zone

            operator: In

            values: ["zone-b"]

2.5. 典型场景

  1. 分区部署:Pod 优先调度到指定可用区;
  2. 机型隔离:高性能应用调度到高配置节点;
  3. 环境隔离:测试 Pod 只跑测试节点,生产只跑生产节点。

2.6. Pod 亲和 podAffinity

让当前 Pod 和 已有指定 Pod 调度到拓扑域内(同节点/同机架/同可用区),实现就近访问、降低网络延迟。

2.7. 核心字段

  • labelSelector:匹配目标 Pod 标签
  • topologyKey:拓扑维度(基于节点标签划分域),常用:
  • kubernetes.io/hostname:按节点划分(同节点)
  • topology.kubernetes.io/zone:按可用区划分
  • topology.kubernetes.io/region:按地域划分

2.8. 示例:硬 Pod 亲和(和 app=redis 的 Pod 同节点)


spec:

  affinity:

    podAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchLabels:

            app: redis  # 目标Pod标签

        topologyKey: kubernetes.io/hostname  # 约束到同一节点

2.9. 适用场景

  • 应用+缓存就近部署,减少跨节点网络开销;
  • 一组关联服务强制部署在同一可用区。

2.10. Pod 反亲和 podAntiAffinity(生产高可用核心)

禁止当前 Pod 和 已有同标签 Pod 部署在同一拓扑域,实现副本打散、单点故障隔离。

线上 Deployment 多副本标配,防止节点宕机导致服务全挂。

2.11. 示例1:硬反亲和(同标签 Pod 不能在同一节点)

Deployment 副本强制打散到不同节点:


apiVersion: apps/v1

kind: Deployment

metadata:

  name: web-demo

spec:

  replicas: 3

  template:

    spec:

      affinity:

        podAntiAffinity:

          requiredDuringSchedulingIgnoredDuringExecution:

          - labelSelector:

              matchLabels:

                app: web  # 自身标签,禁止同标签Pod共处

            topologyKey: kubernetes.io/hostname

效果:3 个副本一定会分布在 3 个不同节点。

2.12. 示例2:软反亲和(尽量打散)

权重控制优先级,资源不足时允许同节点部署:


podAntiAffinity:

  preferredDuringSchedulingIgnoredDuringExecution:

  - weight: 100

    podAffinityTerm:

      labelSelector:

        matchLabels:

          app: web

      topologyKey: kubernetes.io/hostname

2.13. 典型场景

  1. 高可用:无状态服务副本打散到不同节点/可用区;
  2. 资源隔离:同类高负载应用互相隔离,避免争抢资源;
  3. 多租户:不同租户 Pod 隔离。

2.14. 亲和/反亲和 综合对比 & 踩坑

类型作用对象约束方向核心用途
nodeAffinityPod ↔ 节点选节点机型、区域、环境隔离
podAffinityPod ↔ Pod尽量放一起就近访问、低延迟
podAntiAffinityPod ↔ Pod尽量分开高可用、故障隔离

2.15. 常见坑

  1. 硬约束设置过严,集群节点不足 → Pod 永久 Pending;
  2. topologyKey 节点无对应标签 → 规则失效;
  3. 大规模集群大量硬反亲和,调度性能下降。

3. 第二部分:污点 & 容忍(Taint & Toleration)

节点打污点 → 排斥普通 Pod;Pod 配置容忍 → 允许调度到污点节点。

核心用于:节点专用化、节点维护、节点隔离、驱逐 Pod。

3.1. 核心概念

  • 污点(Taint):定义在 Node 上,格式:key=value:effect
  • 容忍(Toleration):定义在 Pod 上,表示“可以容忍该污点”

3.2. 污点三大策略(effect)

3.3. NoSchedule

  • 规则:新 Pod 不允许调度到此节点;已运行的 Pod 不受影响。
  • 场景:临时禁用节点调度、专属业务节点。

3.4. PreferNoSchedule

  • 规则:调度器尽量不将 Pod 调度到此节点(软约束);实在无节点也可调度。
  • 场景:节点资源不足预警、优先避让。

3.5. NoExecute

  • 规则:
  1. 新 Pod 禁止调度;
  2. 已运行在该节点、无对应容忍的 Pod 会被驱逐;
  3. 可设置容忍时长 tolerationSeconds:延迟驱逐。
  • 场景:节点维护、节点故障、 cordon/uncordon。

3.6. 命令行:节点打污点 / 删除污点


# 语法:kubectl taint nodes <节点名> key=value:effect

# 1. 给 node-01 打 NoSchedule 污点

kubectl taint nodes node-01 node-type=db:NoSchedule

# 2. 打 NoExecute 污点,用于节点维护

kubectl taint nodes node-01 maintenance=on:NoExecute

# 3. 删除污点(加减号)

kubectl taint nodes node-01 node-type=db:NoSchedule-

3.7. Pod 容忍配置详解

3.8. 基础语法


spec:

  tolerations:

  - key: "node-type"        # 对应污点 key

    operator: "Equal"       # Equal / Exists

    value: "db"             # Equal 时需要匹配 value

    effect: "NoSchedule"    # 对应污点 effect

3.9. 运算符说明

  1. operator: Equal(默认):key=value 完全匹配污点
  2. operator: Exists:只要节点存在该 key 的污点就容忍(忽略 value)

3.10. 场景1:容忍 NoSchedule 污点(专属节点)

数据库节点打污点,仅数据库 Pod 可调度:


spec:

  tolerations:

  - key: node-type

    operator: Equal

    value: db

    effect: NoSchedule

3.11. 场景2:容忍所有污点(万能容忍,不推荐滥用)


tolerations:

- operator: Exists  # 匹配任意 key、value、effect

3.12. 场景3:NoExecute + 延迟驱逐(维护窗口)

设置 tolerationSeconds: 300,Pod 被标记驱逐后延迟 300s 再销毁,预留业务收尾时间:


tolerations:

- key: maintenance

  operator: Equal

  value: on

  effect: NoExecute

  tolerationSeconds: 300

3.13. 典型生产场景

  1. 专属节点:DB、MQ 中间件节点打 NoSchedule,仅对应组件容忍调度;
  2. 节点维护:节点升级/重启,打 NoExecute 驱逐业务 Pod;
  3. 混合集群隔离:GPU 节点打污点,仅 AI 任务 Pod 可调度;
  4. 集群分区:不同租户、不同环境通过污点隔离节点池。

3.14. 污点+亲和性 组合使用(高阶组合)

流程:

  1. 节点打标签 + 打污点;
  2. Pod 通过 nodeAffinity 选定节点标签;
  3. Pod 通过 tolerations 容忍节点污点。
    实现强隔离专属节点池,生产中间件标准方案。

4. 第三部分:Pod 优先级 & 抢占(PriorityClass)

解决:资源不足时,高优先级 Pod 抢占低优先级 Pod 资源,保障核心业务优先运行。

适用:集群资源满载、突发流量、关键任务保障。

4.1. 核心概念

  1. PriorityClass:全局资源对象,定义优先级名称 & 优先级数值
  2. priorityClassName:Pod/工作负载引用优先级类
  3. 优先级数值范围:0 ~ 10亿,数值越大优先级越高
  4. 抢占机制:高优 Pod 调度失败时,主动驱逐节点上低优 Pod,腾出资源

4.2. 内置默认优先级类

  • system-node-critical:最高优先级,集群核心组件(kube-proxy、coredns)
  • system-cluster-critical:次高,集群基础组件

4.3. 自定义 PriorityClass

4.4. 1)创建 PriorityClass


apiVersion: scheduling.k8s.io/v1

kind: PriorityClass

metadata:

  name: priority-high

value: 10000          # 优先级数值

globalDefault: false  # 是否作为全局默认优先级

description: "高优先级核心业务"

4.5. 2)Pod 引用优先级


apiVersion: v1

kind: Pod

metadata:

  name: high-pod

spec:

  priorityClassName: priority-high

  containers:

  - name: app

    image: nginx

4.6. 抢占机制规则

  1. 集群资源耗尽,高优 Pod 预选通过但资源不足 → 触发抢占;
  2. 调度器从候选节点中,驱逐优先级更低的 Pod;
  3. 被驱逐 Pod 会重新调度到其他节点;
  4. 优先级相同 Pod 不会互相抢占。

4.7. 生产规范 & 限制

  1. 核心业务(订单、支付)设置高优先级;
  2. 测试、离线任务、日志采集设置低优先级;
  3. 禁止普通业务使用超高优先级,避免抢占系统组件;
  4. 抢占会导致 Pod 重建、流量抖动,非必要不开启。

5. 第四部分:Pod 拓扑分布约束(Topology Spread Constraints)

K8s 1.19+ 稳定版,新一代 Pod 打散/均衡策略,比 Pod 反亲和更灵活、功能更强。

目标:让 Pod 副本在多个拓扑域(节点/可用区)均匀分布,提升整体容灾能力。

5.1. 核心字段

  • maxSkew:最大倾斜数(不同拓扑域 Pod 数量差值上限)
  • topologyKey:拓扑维度(节点标签)
  • whenUnsatisfiable:不满足规则时的行为
  • DoNotSchedule:硬约束,不满足则不调度(默认)
  • ScheduleAnyway:软约束,尽量均衡,不满足也调度
  • labelSelector:匹配一组 Pod 进行统计

5.2. 示例:可用区间均匀分布

要求:app=web 的 Pod 在不同可用区差值不超过 1


spec:

  topologySpreadConstraints:

  - maxSkew: 1

    topologyKey: topology.kubernetes.io/zone

    whenUnsatisfiable: DoNotSchedule

    labelSelector:

      matchLabels:

        app: web

5.3. 和 Pod 反亲和区别

  1. Pod 反亲和:一对一隔离(不能同节点);
  2. 拓扑分布:全局均衡(多节点/多可用区均匀打散);
  3. 大规模多副本、多可用区集群,优先使用 拓扑分布约束。

6. 第五部分:节点调度限制(Node 端策略)

6.1. 节点不可调度(Cordon / Uncordon)

手动冻结节点,禁止新 Pod 调度,不驱逐已有 Pod(运维常用)


# 标记节点不可调度

kubectl cordon node-01

# 恢复调度

kubectl uncordon node-01

底层:自动给节点添加 node.kubernetes.io/unschedulable 污点。

6.2. 节点标签调度 + 节点污点综合管控

企业标准节点池划分方案:

  1. 按用途打标签:node-role=app/db/gpu/log
  2. 按区域打标签:topology.kubernetes.io/zone=zone-a
  3. 对应节点打污点,隔离不同业务;
  4. 工作负载使用 nodeAffinity + tolerations 绑定节点池。

7. 第六部分:多调度器 & 调度器扩展(深度高阶)

7.1. 多调度器并行

K8s 允许集群运行多个自定义调度器,不同 Pod 使用不同调度器。

7.2. 1)指定 Pod 使用自定义调度器


spec:

  schedulerName: my-scheduler  # 调度器名称

7.3. 适用场景

  • 离线任务、大数据任务使用专属调度器;
  • 特殊硬件(GPU、FPGA)自定义调度逻辑。

7.4. 调度器扩展框架

7.5. 扩展方式

  1. 调度器插件(Scheduling Framework):K8s 内置框架,替换/新增预选、打分插件(主流)
  2. 外部调度器:独立进程实现全调度逻辑
  3. Admission 准入钩子:调度后二次校验

7.6. 常用官方插件

  • 资源均衡、节点打分、拓扑感知、污点容忍等均以插件形式实现。

8. 第七部分:GPU 设备调度(硬件资源调度)

针对 GPU、RDMA 等异构资源,K8s 通过 Device Plugin 实现调度。

  1. 节点部署 GPU Device Plugin,上报 GPU 卡数量、UUID;
  2. Pod 声明 GPU 资源,调度器筛选有空闲 GPU 的节点;

8.1. 配置示例


spec:

  containers:

  - name: gpu-app

    image: nvidia/cuda

    resources:

      limits:

        nvidia.com/gpu: 1  # 申请1块GPU

特点:GPU 属于独占资源,不支持超配。


9. 生产调度组合最佳实践(落地模板)

9.1. 普通无状态服务(高可用标准)

  1. podAntiAffinity 硬反亲和:副本打散到不同节点;
  2. topologySpreadConstraints:多可用区均匀分布;
  3. 软节点亲和:优先调度到同可用区节点;
  4. 合理设置 Pod 优先级。

9.2. 中间件(DB/MQ 专属节点)

  1. 节点打 NoSchedule 污点;
  2. Pod 配置对应容忍;
  3. 节点亲和锁定专属节点标签;
  4. 高 Pod 优先级,防止被抢占。

9.3. 离线任务(日志、计算、备份)

  1. 低 Pod 优先级;
  2. 节点打 PreferNoSchedule 污点,业务 Pod 优先避让;
  3. 资源宽松,允许超配。

10. 高频面试题(调度必考)

  1. 简述 K8s 默认调度器预选、打分流程?
  2. nodeAffinity、podAffinity、podAntiAffinity 区别与场景?
  3. 污点三种 effect(NoSchedule / PreferNoSchedule / NoExecute)区别?
  4. NoExecute 配合 tolerationSeconds 作用?
  5. Pod 优先级与抢占机制,什么情况下会触发抢占?
  6. 拓扑分布约束和 Pod 反亲和的区别,各自适用场景?
  7. cordon 节点和打 NoExecute 污点有什么不同?
  8. 如何实现中间件专属节点池?(污点 + 容忍 + 节点亲和组合)
  9. 如何让 Deployment 副本强制打散在不同可用区?
  10. 多调度器如何使用?schedulerName 作用?

关联文档

Yanche Blog

记录云原生、Linux、数据库等技术领域的学习心得,以及日常生活的思考与感悟。

© 2026 Yanche Blog. All rights reserved.

Powered by Astro