bigywater.tech
Kubernetes · 53

ReplicaSet 收养:标签匹配的 Pod 被谁接管

标签匹配的 Pod 会被谁接管?改个标签会怎样?两个 selector 一样的 ReplicaSet 会不会打架?这篇用裸 Pod、改标签、orphan 删除和两个重叠的 ReplicaSet,把 ReplicaSet 收养 Pod 的规则一条条跑出来。

uid 不变
裸 Pod 被收养、以及 orphan 之后被新 ReplicaSet 接管时,Pod 都没有重建
SuccessfulDelete: stray2
新建的匹配裸 Pod 被已满足的 ReplicaSet 收养后立即被删除的事件
4 个 Pod
两个 selector 相同、replicas 都是 2 的 ReplicaSet 各管各的,总共的 Pod 数

收养裸 Pod

实测 · 本机执行输出
  裸 Pod stray(标签 app=r):stray→(没有所有者)
  创建 rs-a(replicas=2,selector app=r)之后:rs-a-f45zk→ReplicaSet/rs-a(controller=True); stray→ReplicaSet/rs-a(controller=True)
  stray 的 uid 没变:True;总共 2 个 Pod(收养 1 个 + 新建 1 个);rs-a status:replicas=2 readyReplicas=2
  把 rs-a 缩到 1:rs-a-f45zk→ReplicaSet/rs-a(controller=True)(被删掉的是哪一个由 ReplicaSet 按规则选,这次保留的是上面那一个)

先创建一个标签 app=r 的裸 Pod stray,再创建 replicas: 2、selector: app=r 的 ReplicaSet。stray 的 ownerReferences 立刻多了一条指向这个 ReplicaSet 的、controller: true 的记录——被收养了;uid 没变(没有重建),ReplicaSet 只再新建了 1 个,总共 2 个。缩到 1 个副本时删掉哪个由 ReplicaSet 按规则挑,不一定是被收养的那个。

改标签

实测 · 本机执行输出
  把 rs-a-bfx4j 的标签 app 改成 other:app=r 的 Pod:rs-a-f45zk→ReplicaSet/rs-a(controller=True); rs-a-nqvx8→ReplicaSet/rs-a(controller=True)
    rs-a-bfx4j 现在:(没有所有者),仍在运行;ReplicaSet 补了一个新的(共 2 个 app=r)
  再把标签改回 app=r(它没有所有者了,而 ReplicaSet 现在有 3 个匹配的):rs-a-bfx4j→ReplicaSet/rs-a(controller=True); rs-a-f45zk→ReplicaSet/rs-a(controller=True)
    ReplicaSet 删掉了多余的一个;rs-a-bfx4j 还在吗:True

把一个 Pod 的 app 标签改成 other,它不再匹配 selector,所有者被摘掉成了孤儿、继续运行,ReplicaSet 看到少了一个就补一个新的。再改回 app=r,它又被收养,此时有 3 个匹配的 Pod,ReplicaSet 删掉多余的一个(较新的那个)。排查线上出问题的 Pod 时,改标签把它“拿出来”保留现场、同时让 ReplicaSet 补上新的,是常用办法。

orphan 与接管

实测 · 本机执行输出
  删除 rs-a(orphan):Pod rs-a-bfx4j→(没有所有者); rs-a-f45zk→(没有所有者)
  创建 rs-b(同样的 selector):rs-a-bfx4j→ReplicaSet/rs-b(controller=True); rs-a-f45zk→ReplicaSet/rs-b(controller=True);Pod 的 uid 全都没变:True(没有重建)

kubectl delete rs --cascade=orphan 只删 ReplicaSet,Pod 的所有者被摘掉但仍在运行;创建 selector 相同的新 ReplicaSet 后,两个 Pod 立刻被接管,uid 全部没变。想换 ReplicaSet 的配置又不想重建 Pod,就用这个。

只收养没有控制器的 Pod

实测 · 本机执行输出
  rs-x、rs-y 都是 replicas=2、selector app=r:总共 4 个 Pod:rs-x-c4c56→ReplicaSet/rs-x(controller=True); rs-x-qc6kg→ReplicaSet/rs-x(controller=True); rs-y-qbqnn→ReplicaSet/rs-y(controller=True); rs-y-vgk65→ReplicaSet/rs-y(controller=True)
    rs-x status.replicas=2;rs-y status.replicas=2(各自只数自己所有的 Pod)
  再创建一个标签匹配的裸 Pod stray2(现在 rs-x、rs-y 都已经满足 replicas=2):NotFound(+0.0s)
    ReplicaSet 的事件里提到 stray2 的:rs-y SuccessfulDelete: Deleted pod: stray2 | stray2 Scheduled: Successfully assigned k47/stray2 to kx-main-worker2
    最后:rs-x-c4c56→ReplicaSet/rs-x(controller=True); rs-x-qc6kg→ReplicaSet/rs-x(controller=True); rs-y-qbqnn→ReplicaSet/rs-y(controller=True); rs-y-vgk65→ReplicaSet/rs-y(controller=True)(总共 4 个,仍然是 4 个)

两个 selector 完全相同的 ReplicaSet(rs-x、rs-y,各 replicas: 2)并不会互相抢:每个 Pod 只有一个控制器所有者,两边各管各的 2 个,status.replicas 都是 2,共 4 个 Pod。但此后新建的、标签匹配的裸 Pod stray2 没有所有者,会被其中一个(这次是 rs-y)收养,而它们已经满足副本数,于是立刻被当作多余的删掉:事件 SuccessfulDelete: Deleted pod: stray2,0.0 秒内就查不到了。这也是不要让 selector 重叠的原因。

分步演示

ReplicaSet 收养
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);Pod 是 busybox:1.36 sleep;所有者信息取自每个 Pod 的 metadata.ownerReferences;每次操作后等 3~5 秒再读取(第 4 节的 stray2 用 0.1 秒轮询,第一次查询就已 NotFound,所以靠事件确认它被收养后又被删除);每种情形各一次,Pod 名字后缀每次运行不同
    • 没有验证:Deployment 与 ReplicaSet 的收养关系(pod-template-hash 标签如何防止多个 ReplicaSet 互相收养);selector 与 Pod 模板标签不匹配时 ReplicaSet 创建被拒绝;ReplicaSet 缩容时选哪个 Pod 删除的完整排序规则(未就绪、较新、所在节点上同类更多的优先);Pod 的 controller=false 的 ownerReference 不阻止收养;垃圾回收对孤儿 Pod 的处理(见垃圾回收一篇)
    京ICP备2026067502号-1京公网安备11010502063487号