属主与附属
在 Kubernetes 中,一些对象是其他对象的属主(Owner),例如 ReplicaSet 是一组 Pod 的属主。具有属主的对象是属主的附属(Dependent)。
属主关系不同于标签和选择算符机制。例如一个 Service 会创建 EndpointSlice 对象:Service 使用标签让控制平 面确定哪些 EndpointSlice 属于该 Service;除此之外,每个由 Service 管理的 EndpointSlice 还有一个属主引用。属主引用能避免 Kubernetes 的不同部分干扰到不受它们控制的对象。
官方文档参考
| 文档 | 语言 | 链接 |
|---|---|---|
| 属主与附属(Owners and Dependents)概念页 | 中文 | https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/owners-dependents/ |
| Owners and Dependents 概念页(英文,用于补全跨名字空间限制等细节) | 英文 | https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/ |
对象规约中的属主引用
附属对象通过 metadata.ownerReferences 字段引用其属主。一个有效的属主引用包含:
| 要求 | 说明 |
|---|---|
| 对象名称 | 属主对象的名称 |
| UID | 属主对象的唯一标识,防止同名新对象被误认为属主 |
| 同名字空间 | 名字空间型属主必须与附属对象处于同一个名字空间 |
Kubernetes 会为一些对象的附属资源自动设置属主引用,包括 ReplicaSet、DaemonSet、Deployment、Job、CronJob、ReplicationController 等。你也可以手动修改该字段来配置关系,但通常不需要,交给 Kubernetes 自动管理即可。
附属对象还有一个 ownerReferences.blockOwnerDeletion 字段(布尔值),控制该附属是否可以阻止垃圾收集删除其属主对象。当控制器(例如 Deployment 控制器)设置 metadata.ownerReferences 时,Kubernetes 自动将此字段设为 true。Kubernetes 用一个准入控制器基于用户对属主的删除权限来限制对该字段的修改,防止未授权用户延迟属主对象的删除。
一个典型的 Pod 属主引用如下:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
ownerReferences:
- apiVersion: apps/v1
kind: ReplicaSet # 属主类型
name: nginx-replicaset # 属主名称
uid: 1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d # 属主 UID,删除同名重建的属主不会误连
controller: true # 标记属主即管理本对象的控制器
跨名字空间的属主引用
- 名字空间型的附属可以指定集群范围的属主或同名 字空间的属主;名字空间型属主必须与附属在同一名字空间,否则该属主引用被视作不存在,附属在确认所有属主都不存在后会被删除。
- 集群范围的附属只能指定集群范围的属主。在 v1.20 及以上版本,若集群范围的附属引用了名字空间型的属主,该属主引用被视为无法解析,附属无法被垃圾回收。
- v1.20+ 垃圾收集器检测到无效跨名字空间属主引用时,会报告一条 reason 为
OwnerRefInvalidNamespace的警告事件。可用以下命令排查:
kubectl get events -A --field-selector=reason=OwnerRefInvalidNamespace
属主关系与 Finalizers
当请求删除某个资源时,API 服务器允许管理该资源的控制器先处理它的 Finalizer 规则。Finalizer 防止误删集群仍需要的资源:
- 例如删除一个仍被 Pod 使用的 PersistentVolume 时,删除不会立即发生,因为 PV 上 有
kubernetes.io/pv-protectionFinalizer;卷会一直保持 Terminating 状态,直到不再与任何 Pod 绑定后 Kubernetes 才清除该 Finalizer。 - 使用前台(foreground) 或孤立(orphan) 级联删除时,Kubernetes 也会给属主资源加上对应的 Finalizer:
- foreground:加上
foregroundFinalizer,控制器必须先删除所有blockOwnerDeletion=true的附属,再删除属主; - orphan:加上
orphanFinalizer,控制器在删除属主对象后不管(孤立化)附属资源。
- foreground:加上
级联删除与垃圾回收
垃圾收集器(Garbage Collector)根据属主引用决定附属对象的去留。kubectl delete 时通过 --cascade 参数控制级联行为:
| 级联模式 | 参数值 | 行为 |
|---|---|---|
| 后台级联删除(默认) | --cascade=background | 先删除属主,垃圾收集器随后在后台清理附属 |
| 前台级联删除 | --cascade=foreground | 属主进入 Terminating,先删除全部附属,最后删除属主本身 |
| 孤立删除 | --cascade=orphan | 只删除属主本身,附属被"孤立"(解除属主引用)继续存活 |
# 后台删除:属主立即消失,附属由 GC 稍后清理
kubectl delete replicaset nginx-replicaset --cascade=background
# 前台删除:直到所有附属删除完成,属主才消失
kubectl delete replicaset nginx-replicaset --cascade=foreground
# 孤立删除:Pod 保留下来,ownerReferences 被清除
kubectl delete replicaset nginx-replicaset --cascade=orphan
我的总结与避坑清单
- 依赖关系优先用属主引用而不是标签:删除属主能自动带走附属,靠标签关联的对象删除时不会级联,容易留垃圾。
- 不要手动构造跨名字空间的 ownerReferences——轻则引用失效导致附属被误删,重则集群范围对象挂在无效引用上永远无法被 GC;出现异常时先查
OwnerRefInvalidNamespace事件。 - 属主引用里的 UID 是关键防误删机制:删除同名重建的属主不会"认领"旧的附属;反过来,手动复用旧配置(含旧 UID)会让关系失效。
- PV 卡 Terminating 多半是
kubernetes.io/pv-protectionFinalizer 在起作用,先检查是否还有 Pod 在使用该卷,而不是强行删除。 - 生产环境慎用
--cascade=orphan:孤立出来的资源脱离了控制器管理(如孤立 Pod 不再有 ReplicaSet 保障副本数),常用于迁移场景,用完记得手工接管或清理。 - 删除大对象树(如 Deployment 带大量 Pod)时优先用默认的 background 删除避免 API 压力;需要"删干净才继续"的发布/清理流程用 foreground。

