bigywater.tech
Kubernetes · 45

亲和与反亲和:required 与 preferred 的差别

required 和 preferred 差在哪?反亲和写错了会怎样?调度之后条件变了,Pod 会被赶走吗?这篇用一个带 zone 与 cores 标签的集群,把 nodeAffinity、podAffinity、podAntiAffinity 的硬软两种写法逐个真跑了一遍。

worker3=3 worker4=3
两个 nodeSelectorTerms(OR)分别匹配 zone b 与 zone c 时 6 个副本的分布
4 + 1 Pending
podAntiAffinity required 的 5 个副本在 4 个 worker 上的结果
3 个 Pod 不动
被亲和的 cache 删掉之后,已经运行的 web Pod 的去向

nodeAffinity:硬与软

实测 · 本机执行输出
  required zone In [b](4 个副本):节点 worker3=4
  required cores Gt 6 且 zone NotIn [c](同一个 matchExpressions 里的条件是 AND):节点 worker3=4(只有 cores=8 的 worker3 满足)
  两个 nodeSelectorTerms(之间是 OR):zone In [b] 或 zone In [c]:节点 worker3=3 worker4=3
  preferred zone=c(weight 100,8 个副本):节点 worker4=8

required…IgnoredDuringExecution 是硬条件:zone In [b] 的 4 个副本全部在 worker3;matchExpressions 里的多个条件是 AND(cores Gt 6 且 zone NotIn [c] 只剩 worker3),而多个 nodeSelectorTerms 之间是 OR(zone b 或 zone c,得到 worker3=3、worker4=3)。preferred 只是加分:zone=c(weight 100)的 8 个副本全部去了 worker4,但如果 worker4 放不下,它们仍会去别处。

required 反亲和会卡住

实测 · 本机执行输出
  5 个副本、4 个可用的 worker(控制面有污点):节点 worker=1 worker2=1 worker3=1 worker4=1;Pending 1 个
    Pending Pod 的原因:0/5 nodes are available: 1 node(s) had untolerated taint(s), 4 node(s) didn't match pod anti-affinity rules. preemption: 0/5 nodes are available: 1 Preemption is not helpful for scheduling, 4 No preem
  缩到 4 个副本:节点 worker=1 worker2=1 worker3=1 worker4=1

podAntiAffinity required、topologyKey: kubernetes.io/hostname、同一个标签:每个节点最多 1 个。5 个副本、4 个可用的 worker(控制面有污点)只放下 4 个,第 5 个 Pending:1 node(s) had untolerated taint(s), 4 node(s) didn't match pod anti-affinity rules。副本数大于节点数时,用 required 就等于故意留 Pod 在 Pending。

preferred 反亲和

实测 · 本机执行输出
  5 个副本:节点 worker=1 worker2=1 worker3=1 worker4=2(全部都调度了)
  扩到 9 个:节点 worker=2 worker2=2 worker3=2 worker4=3

改成 preferred(weight 100)之后 5 个副本全部调度,分布 1/1/1/2;扩到 9 个也都能调度(2/2/2/3)。它只影响打分:尽量分开,放不下就挤在一起,永远不会让 Pod 无法调度。想要“尽量均匀”应该用它,或者上一篇的 topologySpreadConstraints。

IgnoredDuringExecution

实测 · 本机执行输出
  web 要求和 app=cache 的 Pod 在同一个节点(podAffinity required,hostname):节点 worker3=3(cache 在 worker3)
  删掉 cache 之后:已经运行的 web Pod 节点 worker3=3(没有被驱逐)
  把 web 扩到 5 个:节点 worker3=3;Pending 2 个;Pending 原因:0/5 nodes are available: 1 node(s) had untolerated taint(s), 4 node(s) didn't match pod affinity rules. preemption: 0/5 nodes are available: 5 Preemption is not helpful for scheduling.
  nodeAffinity required zone In [b] 的 2 个 Pod 调度后,把 worker3 的 zone 标签删掉:节点 worker3=2(没有被驱逐);再加 1 个副本:节点 worker3=2;Pending 1 个;原因:0/5 nodes are available: 1 node(s) had untolerated taint(s), 4 node(s) didn't match Pod's node affinity/selector. preemption: 0/5 nodes are available: 5 Preemption is not helpful for scheduling.

名字里的这个词意思是:只在调度那一刻检查。web 要求和 cache 同节点,3 个都在 worker3;把 cache 删掉,web 的 3 个 Pod 不会被驱逐,但扩容出来的新副本 Pending(didn't match pod affinity rules)。节点亲和也一样:调度后把 worker3 的 zone 标签删掉,已经在运行的 Pod 不动,新副本 Pending(didn't match Pod's node affinity/selector)。结果是新旧副本分布可能不一致。

分步演示

亲和与反亲和
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。独立的 5 节点 kind 集群 kx-sched(1 控制面 + 4 个 worker,Kubernetes v1.37.0,与拓扑分布一篇共用),zone 与 cores 标签由脚本打上并在实验后删除;Deployment 的 Pod 是 busybox:1.36;分布取自每个 Pod 的 spec.nodeName,Pending 原因取自 PodScheduled 条件的 message;第 4 节的 cache 用 nodeName 固定在 worker3;每种情形各一次
    • 没有验证:requiredDuringSchedulingRequiredDuringExecution(尚未实现);podAffinity 的 namespaceSelector 与 matchLabelKeys;多个 preferred 的权重相加规则;反亲和对大规模集群调度性能的影响;Pod 自己匹配自己的亲和(第一个副本的特殊处理);亲和与抢占的交互
    京ICP备2026067502号-1京公网安备11010502063487号