Skip to content

用费曼学习法学懂 K8s 调度全套规则 ​

费曼核心逻辑:用大白话类比 → 讲清本质 → 给实操例子 → 总结用法 我全程不用晦涩术语,把调度器当成给 Pod 找房子的中介,你一听就懂。


0. 先搞懂:谁在调度?调度的本质是什么? ​

K8s 里有个组件叫 kube-scheduler,它就是专属中介。 Pod 刚创建出来没地方跑,中介就按照你定的规则,从所有 Node 里挑一个最合适的,把 Pod 安排过去。

今天讲的 4 套东西,就是中介的筛选规则:

  1. 标签选择器(最基础的硬筛选)
  2. 节点亲和 / 反亲和(喜欢/讨厌哪些机器)
  3. Pod 亲和 / 反亲和(要跟谁住一起/分开)
  4. 污点 & 容忍(机器挂“禁止入内”,Pod 带“通行证”)

1. 标签选择器 nodeSelector(最基础、最粗暴) ​

大白话类比 ​

给 Node 贴身份标签(比如 disk=ssd、env=prod), Pod 说:我只去贴了 XX 标签的机器,别的不去。

本质 ​

硬匹配:有标签就收,没标签就滚 没有商量余地,不满足直接调度失败。

实操 YAML ​

yaml
nodeSelector:
  disk: ssd       # 只调度到有 disk=ssd 标签的节点

适用场景 ​

  • 简单区分:SSD 节点、GPU 节点、测试/生产节点
  • 简单、直接,但不够灵活(只有“是/否”,没有“优先”)

2. 节点亲和 & 反亲和(Node Affinity) ​

大白话类比 ​

  • 节点亲和:Pod 说「我优先/必须住朝南的房间」
  • 节点反亲和:Pod 说「我尽量/绝对不住一楼」

两种强度(必考+必用) ​

  1. required...(硬约束) 不满足 → 绝对不调度,Pod 一直 Pending
  2. preferred...(软偏好) 能满足最好,满足不了也能调度,不卡死

关键词 ​

  • requiredDuringSchedulingIgnoredDuringExecution 调度时必须满足,运行后节点标签变了也不驱逐 Pod
  • preferredDuringSchedulingIgnoredDuringExecution 调度时尽量满足

节点亲和 YAML 示例 ​

yaml
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: disk
          operator: In
          values: ["ssd"]

节点反亲和(例子:不去生产节点) ​

yaml
- key: env
  operator: NotIn
  values: ["prod"]

适用场景 ​

  • 必须把数据库放到 SSD 节点
  • 测试 Pod 绝对不跑到生产机器
  • 优先把服务调度到空闲节点

3. Pod 亲和 & 反亲和(最常用、最关键) ​

大白话类比 ​

不是看机器,而是看邻居:

  • Pod 亲和:我要跟「某某 Pod」住同一个节点/机架 例:Web 要和 Redis 放一起,降低延迟
  • Pod 反亲和:我不要跟「某某 Pod」住一起 例:两个相同的微服务,别放一台机器,防止机器挂了服务全挂

核心概念:拓扑域 topologyKey ​

决定“多近算一起”:

  • kubernetes.io/hostname = 同一个节点
  • topology.kubernetes.io/zone = 同一个可用区

Pod 反亲和(生产最常用!防止单点) ​

yaml
affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: app
          operator: In
          values: ["nginx"]
      topologyKey: kubernetes.io/hostname

意思:同一个节点里,不许出现第二个 app=nginx 的 Pod

适用场景 ​

  • 高可用:相同副本分散到不同节点
  • 核心服务避免单点故障
  • 服务间就近访问(Pod 亲和)

4. 污点 & 容忍(Taints & Tolerations) ​

大白话类比 ​

前面都是Pod 挑机器 污点是:机器主动挂牌子:闲人免进!

  • 污点(Taint):Node 贴拒绝标签
  • 容忍(Toleration):Pod 带通行证,才能进去

三种污点效果 ​

  1. NoSchedule:新 Pod 不调度进来,老 Pod 没事
  2. PreferNoSchedule:尽量别调度进来
  3. NoExecute:直接把不符合的 Pod 驱逐走

最经典例子:Master 节点 ​

master 节点默认有污点:

node-role.kubernetes.io/control-plane:NoSchedule

普通 Pod 进不去,只有控制面组件带容忍才能运行。

给 Node 打污点 ​

bash
kubectl taint nodes k8s-node-01 gpu=true:NoSchedule

Pod 写容忍(通行证) ​

yaml
tolerations:
- key: gpu
  operator: Equal
  value: "true"
  effect: NoSchedule

适用场景 ​

  • master 节点隔离
  • GPU 节点专用
  • 特殊硬件节点专用
  • 节点维护时驱逐 Pod

5. 四者关系 + 调度执行顺序(面试必问) ​

中介真正干活的顺序是:

  1. 先看污点:有污点且没容忍 → 直接排除
  2. 再看节点亲和/反亲和:过滤喜欢/讨厌的机器
  3. 再看 Pod 亲和/反亲和:看邻居合不合适
  4. 最后看 nodeSelector:硬匹配标签

一句话总结区别 ​

  • nodeSelector:硬筛选,简单粗暴
  • 节点亲和:Pod 挑机器,支持软硬规则
  • Pod 亲和:Pod 挑邻居,实现就近/高可用
  • 污点容忍:机器拒 Pod,实现专用节点隔离

6. 生产最常用组合(你必须记住) ​

  1. 微服务高可用:Pod 反亲和 + hostname 拓扑域 → 相同副本绝不挤一台机器
  2. 数据服务:节点亲和 + SSD 标签 → 保证性能
  3. 集群隔离:Master 污点 + 组件容忍 → 保证控制面安全
  4. 混合部署:节点污点 + 业务容忍 → 测试/生产混部不打架

7. 费曼式自测(你能答出来就学会了) ​

  1. nodeSelector 和节点亲和有啥区别?
  2. Pod 反亲和解决什么问题?topologyKey 干嘛用?
  3. 污点是谁设置的?容忍是谁加的?
  4. NoSchedule 和 NoExecute 差别是什么?
  5. 调度器先看污点还是先看亲和?

你要是愿意,我可以给你出一套带场景的面试题,你答我改,保证彻底吃透调度这块。

用 VitePress 构建