Appearance
用费曼学习法学懂 K8s 调度全套规则
费曼核心逻辑:用大白话类比 → 讲清本质 → 给实操例子 → 总结用法 我全程不用晦涩术语,把调度器当成给 Pod 找房子的中介,你一听就懂。
0. 先搞懂:谁在调度?调度的本质是什么?
K8s 里有个组件叫 kube-scheduler,它就是专属中介。 Pod 刚创建出来没地方跑,中介就按照你定的规则,从所有 Node 里挑一个最合适的,把 Pod 安排过去。
今天讲的 4 套东西,就是中介的筛选规则:
- 标签选择器(最基础的硬筛选)
- 节点亲和 / 反亲和(喜欢/讨厌哪些机器)
- Pod 亲和 / 反亲和(要跟谁住一起/分开)
- 污点 & 容忍(机器挂“禁止入内”,Pod 带“通行证”)
1. 标签选择器 nodeSelector(最基础、最粗暴)
大白话类比
给 Node 贴身份标签(比如 disk=ssd、env=prod), Pod 说:我只去贴了 XX 标签的机器,别的不去。
本质
硬匹配:有标签就收,没标签就滚 没有商量余地,不满足直接调度失败。
实操 YAML
yaml
nodeSelector:
disk: ssd # 只调度到有 disk=ssd 标签的节点适用场景
- 简单区分:SSD 节点、GPU 节点、测试/生产节点
- 简单、直接,但不够灵活(只有“是/否”,没有“优先”)
2. 节点亲和 & 反亲和(Node Affinity)
大白话类比
- 节点亲和:Pod 说「我优先/必须住朝南的房间」
- 节点反亲和:Pod 说「我尽量/绝对不住一楼」
两种强度(必考+必用)
- required...(硬约束) 不满足 → 绝对不调度,Pod 一直 Pending
- preferred...(软偏好) 能满足最好,满足不了也能调度,不卡死
关键词
requiredDuringSchedulingIgnoredDuringExecution调度时必须满足,运行后节点标签变了也不驱逐 PodpreferredDuringSchedulingIgnoredDuringExecution调度时尽量满足
节点亲和 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 带通行证,才能进去
三种污点效果
- NoSchedule:新 Pod 不调度进来,老 Pod 没事
- PreferNoSchedule:尽量别调度进来
- NoExecute:直接把不符合的 Pod 驱逐走
最经典例子:Master 节点
master 节点默认有污点:
node-role.kubernetes.io/control-plane:NoSchedule普通 Pod 进不去,只有控制面组件带容忍才能运行。
给 Node 打污点
bash
kubectl taint nodes k8s-node-01 gpu=true:NoSchedulePod 写容忍(通行证)
yaml
tolerations:
- key: gpu
operator: Equal
value: "true"
effect: NoSchedule适用场景
- master 节点隔离
- GPU 节点专用
- 特殊硬件节点专用
- 节点维护时驱逐 Pod
5. 四者关系 + 调度执行顺序(面试必问)
中介真正干活的顺序是:
- 先看污点:有污点且没容忍 → 直接排除
- 再看节点亲和/反亲和:过滤喜欢/讨厌的机器
- 再看 Pod 亲和/反亲和:看邻居合不合适
- 最后看 nodeSelector:硬匹配标签
一句话总结区别
nodeSelector:硬筛选,简单粗暴节点亲和:Pod 挑机器,支持软硬规则Pod 亲和:Pod 挑邻居,实现就近/高可用污点容忍:机器拒 Pod,实现专用节点隔离
6. 生产最常用组合(你必须记住)
- 微服务高可用:Pod 反亲和 +
hostname拓扑域 → 相同副本绝不挤一台机器 - 数据服务:节点亲和 + SSD 标签 → 保证性能
- 集群隔离:Master 污点 + 组件容忍 → 保证控制面安全
- 混合部署:节点污点 + 业务容忍 → 测试/生产混部不打架
7. 费曼式自测(你能答出来就学会了)
- nodeSelector 和节点亲和有啥区别?
- Pod 反亲和解决什么问题?topologyKey 干嘛用?
- 污点是谁设置的?容忍是谁加的?
- NoSchedule 和 NoExecute 差别是什么?
- 调度器先看污点还是先看亲和?
你要是愿意,我可以给你出一套带场景的面试题,你答我改,保证彻底吃透调度这块。