Skip to content

标签与资源关系

Kubernetes 里的资源不是按“文件顺序”关联的,而是通过标签、选择器、名称引用和 ownerReference 建立关系。Deployment 管哪些 Pod、Service 转发到哪些 Pod、NetworkPolicy 作用在哪些 Pod、Prometheus 采集哪些 Service,本质上都依赖这些关联规则。

标签和资源关系写错时,API Server 不一定报错。Service selector 匹配不到 Pod,Service 仍然能创建成功;NetworkPolicy selector 写宽了,可能影响更多 Pod;ConfigMap 名称写错,Pod 到挂载阶段才暴露错误。排查时要把资源之间的连接线还原出来,而不是只看单个 YAML。

一、labels 和 annotations

labels 是可匹配的键值对,annotations 是附加说明和扩展参数。

yaml
metadata:
  name: web
  namespace: demo
  labels:
    app: web
    env: prod
    version: v1
  annotations:
    kubernetes.io/change-cause: "release web v1"
字段典型用途
labels被 selector 匹配,用来建立资源关系
annotations保存说明、变更记录、控制器扩展参数,不参与 selector 匹配

标签一般放稳定、低基数、可选择的维度,比如 appenvtierversion。Pod IP、时间戳、请求 ID 这类高变化字段不适合做 label。监控和日志系统也会读取 Kubernetes label,高基数标签容易把 Prometheus、Loki 这类后端拖得很重。

二、selector 怎么选中对象

Deployment 通过 selector 找自己管理的 Pod:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: demo
spec:
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web      # Pod 模板标签必须和 selector 对上
    spec:
      containers:
        - name: nginx
          image: nginx:1.26

Service 也通过 selector 找后端 Pod:

yaml
apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: demo
spec:
  selector:
    app: web
  ports:
    - name: http
      port: 80
      targetPort: 80

关系图如下:

Service 不直接保存 Pod IP。selector 选中 Pod 后,控制器生成 EndpointSlice,Service 转发时再走这些 endpoint。

bash
kubectl get pod -n demo --show-labels
kubectl get pod -n demo -l app=web
kubectl get svc web -n demo -o yaml
kubectl get endpointslice -n demo -l kubernetes.io/service-name=web

kubectl get endpoints 在新版本里仍常见,但 EndpointSlice 才是更细粒度的后端对象。Service 不通时,EndpointSlice 为空通常说明 selector 没选中 Ready Pod,或者 Pod readiness 没通过。

三、matchLabels 和 matchExpressions

selector 不只有精确匹配。复杂场景可以用 matchExpressions

yaml
selector:
  matchExpressions:
    - key: app
      operator: In
      values:
        - web
        - api
    - key: env
      operator: NotIn
      values:
        - test

常见 operator:

operator含义
Inkey 的值在指定列表中
NotInkey 的值不在指定列表中
Exists存在这个 key
DoesNotExist不存在这个 key

NetworkPolicy、PodDisruptionBudget、TopologySpreadConstraints、ServiceMonitor 都会用到 selector。写复杂 selector 时,先用 kubectl get pod -l ... 验证匹配范围,比直接 apply 后再猜影响面更清楚。

四、ownerReference——父子关系和垃圾回收

控制器创建子资源时会写入 ownerReference。Deployment 创建 ReplicaSet,ReplicaSet 创建 Pod:

查看 Pod 的 ownerReference:

bash
kubectl get pod <pod-name> -n demo -o yaml | grep -A12 ownerReferences

典型输出:

yaml
ownerReferences:
  - apiVersion: apps/v1
    kind: ReplicaSet
    name: web-6f7c9c9c9b
    uid: 4d2b0c5e-1111-2222-3333-444455556666
    controller: true

ownerReference 影响垃圾回收。删除 Deployment 时,Kubernetes 能沿着 ownerReference 删除 ReplicaSet 和 Pod。直接删除 Pod 时,ReplicaSet 会发现实际副本数少了,再创建一个新的 Pod。

这种差异在排查“Pod 删了又回来”时很常见。Pod 自己不是根对象,背后的 ReplicaSet、Deployment、StatefulSet 或 DaemonSet 才是维持状态的控制器。

五、名称引用

有些资源关系不靠 selector,而是直接写对象名称。

关系字段
Pod 引用 ConfigMapspec.containers[].envFrom[].configMapRef.namespec.volumes[].configMap.name
Pod 引用 SecretsecretKeyRef.nameimagePullSecrets[].namespec.volumes[].secret.secretName
Pod 引用 PVCspec.volumes[].persistentVolumeClaim.claimName
Ingress 引用 Servicespec.rules[].http.paths[].backend.service.name
HTTPRoute 引用 Servicespec.rules[].backendRefs[].name
ServiceMonitor 引用 Servicespec.selector.matchLabels 匹配 Service label

名称引用写错通常不会在 YAML 解析阶段失败,而是在运行阶段表现为挂载失败、镜像拉取失败、路由无后端或采集目标缺失。

bash
kubectl describe pod <pod-name> -n demo
kubectl get events -n demo --sort-by=.lastTimestamp

Events 里常见 not foundfailed to sync configmap cacheMountVolume.SetUp failedsecret not found。这类错误先核对 namespace,再核对名称。

六、资源关系图

一个常见 Web 服务会同时涉及配置、密钥、工作负载、Service 和入口资源:

按关系排查比直接翻全部 YAML 更稳:

现象先看哪里
入口访问 404/503HTTPRoute/Ingress 是否指向正确 Service
Service 不通EndpointSlice 是否有 Ready 后端
Pod 启动失败Events、镜像、挂载、探针
配置没生效Pod 挂载的 ConfigMap/Secret 名称和内容
监控没采到Service label、ServiceMonitor selector、端口名称

Kubernetes 资源关系的难点不在单个字段,而在这些字段把对象连成一张图。图上的某条线断了,表现出来可能是网络不通、Pod 不 Ready、日志采不到、告警没触发。