[Kubernetes] 启动了3个Pod,为什么都集中在一个节点上? (调度器的秘密) 🧐

在运营Kubernetes时,您可能会遇到“咦?这个怎么会出现在这里?”的时刻。最常见的误解就是认为“Pod会均匀地(Round-Robin)分布到各个节点上。”

今天,我将通过我亲身经历的“Pod集中现象”,深入剖析Kubernetes调度器实际如何打分和选择节点,揭示其看不见的逻辑。🚀

image

0. 问题情况:“明明有多个节点…”

为了测试,我依次创建了MySQL、Nginx和httpd的Pod。我们自然而然的期望是“节点1、节点2、节点3…会这样友好地分配开来吧?”

但现实却不同。

$ kubectl get pod -o wideNAME    READY   STATUS    RESTARTS   AGE   IP           NODE                               NOMINATED NODEmysql   1/1     Running   0          66m   10.16.2.12   gke-cluster-1-default-pool-rr03    nx      1/1     Running   0          16m   10.16.2.13   gke-cluster-1-default-pool-rr03    nx1     1/1     Running   0          6s    10.16.2.14   gke-cluster-1-default-pool-rr03    httpd   1/1     Running   0          4s    10.16.2.15   gke-cluster-1-default-pool-rr03    

如您所见,mysql、nx,甚至不同的镜像httpd,都持续不断地只在rr03这一个节点上创建。而其他节点却空空如也!😱

原因是什么呢?调度器是不是坏了?


1. 解开误解:调度器不懂ABC顺序 ❌

很多人认为调度器采用‘轮询(Round-Robin)’方式,就会按照节点名称顺序(A->B->C)进行部署。然而,Kubernetes调度器是完全基于‘分数(Score)’来运作的。

  1. Filtering: 不符合条件的节点被淘汰
  2. Scoring: 给剩余节点打分(0~100分)
  3. Ranking: 选择得分最高的节点

也就是说,rr03节点之所以一直被选中,并非因为顺序,而是在调度器看来,rr03一直都是‘最佳候选’。


2. 嫌犯分析:为什么一个已满的节点会成为第一名? 🤔

在有空节点的情况下,一个已经有3个Pod的节点却成为第一名,这是两种设置的共同作用

① 未设置资源请求(Requests)= 被视为“透明人”

我在创建Pod时没有设置`resources.requests`(CPU/内存请求量)。

  • 调度器的视角:“这个Pod使用0 CPU,0内存?”
  • 判断:无论rr03节点上有100个还是1000个Pod,如果只有未设置Request的Pod,那么在调度器看来,该节点的利用率仍然是‘0%’。
  • 结果:“空节点和rr03反正都一样空闲?(资源分数平局)”

② 决定性一击:镜像本地性(Image Locality)与层共享

这里产生了一个疑问:“如果分数平局,应该随机选择才对,为什么偏偏是rr03?”

罪魁祸首是ImageLocality的加分

  • 部署Nginx时:因为mysql,去已经下载了镜像的节点会更快,所以选择了rr03(可以理解)
  • 部署Httpd时:“咦?这是一个新镜像啊?”
  • 然而,Docker镜像具有层(Layer)结构。
  • mysql、nginx和httpd虽然不同,但它们极有可能共享底层的基础镜像(如Debian、Alpine等)或公共库层。
  • 最终判定:
  • 空节点:“需要从头开始下载所有基础层” -> 无加分
  • rr03节点:“咦?旁边那些Pod用的基础层已经有了?赚到了!” -> 获得加分(+)

最终,资源分数平局(0分影响),但在镜像缓存分数上rr03略微领先,从而成为了一个不断吸纳Pod的黑洞。🕳️


3. 解决方案:如何分散Pod? 🛠️

如何才能阻止这种现象,并将Pod均匀地分散到整个集群中呢?

✅ 方法1:明确指定资源请求(Requests)(推荐)

给Pod贴上“我需要这么多资源!”的标签。

resources:  requests:    cpu: "200m" # 请求0.2核心

这样,调度器就会正常判断“啊,rr03已经满了。应该发送到空节点!”,从而启动负载均衡(Least Allocated)逻辑。

✅ 方法2:设置反亲和性(Anti-Affinity)

这是一种强制设置,表示“我不喜欢和与我相同的Pod待在一起!”。

podAntiAffinity:  requiredDuringSchedulingIgnoredDuringExecution:    - labelSelector: ...

使用此选项,Pod将强制不重叠地部署,与分数计算无关。


4. 结论 📝

  1. Kubernetes调度器不按ABC顺序部署。
  2. 如果未设置requests,调度器会将Pod的大小视为‘0’
  3. 在这种情况下,即使只有少量镜像层残留的节点也会获得加分,导致Pod集中在一个地方。
  4. 为了稳定运行,设置Resource Requests并非可选项,而是必需项!

今天的摸索到此结束!希望这能帮助您理解这位高傲的调度器的心思。👋


Comments

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注