bigywater.tech
Kubernetes · 104

标签与选择器:集合式表达式

-l 'env!=prod' 会选中什么?Deployment 的 selector 为什么改不了?标签值有什么限制?改一个 Pod 的标签会发生什么?这篇用六个不同标签的对象,把选择器语法、控制器的限制和实时影响都跑一遍。

!= 会选到无标签的
env!=prod 与 env notin (prod) 的结果都包含没有 env 标签的对象
63
标签值和键名部分的最大长度(字节)
0.1 秒
改掉 Pod 的 app 标签后,Service 的 endpoint 从 3 变成 2 所用的时间

kubectl 的选择器语法

实测 · 本机执行输出
  -l env=prod                  → ['a', 'b']  (等值)
  -l env!=prod                 → ['c', 'd', 'e', 'f']  (不等于:包括没有 env 标签的)
  -l env=prod,tier=web         → ['a']  (逗号 = 与(AND))
  -l env in (prod,staging)     → ['a', 'b', 'c']  (集合:在其中)
  -l env notin (prod)          → ['c', 'd', 'e', 'f']  (notin:同样包括没有 env 标签的)
  -l env                       → ['a', 'b', 'c', 'd']  (存在这个键)
  -l !env                      → ['e', 'f']  (不存在这个键)
  -l env=dev,!tier             → ['d']  (组合:env=dev 且没有 tier)
  注意:没有“或”的写法能跨键:env=prod OR tier=web 只能分两次查;同一个键内的“或”用 in (a,b)

六个 ConfigMap:a=prod/web,b=prod/db,c=staging/web,d=dev,e=只有 tier=web,f=无标签。-l env=prod → a、b;env!=prod → c、d、e、f(不等于包括没有 env 标签的);env=prod,tier=web(逗号是 AND)→ a;env in (prod,staging) → a、b、c;env notin (prod) 同样包含没有 env 的;env(存在)→ a、b、c、d;!env(不存在)→ e、f;env=dev,!tier → d。跨键的“或”没有一次查完的写法,同一个键内的“或”用 in。

控制器里的选择器

实测 · 本机执行输出
  matchExpressions(app In [frontend,backend] 且 tier 不存在),模板标签 app: frontend:退出码 0;['deployment.apps/d-expr created']
  选择器 app=backend 但模板标签是 app: frontend:退出码 1;['The Deployment "d-mismatch" is invalid: spec.template.metadata.labels: Invalid value: {"app":"frontend"}: `selector` does not match template `labels`']
  选择器写成 {}(空):退出码 1;['The Deployment "d-empty" is invalid: spec.selector: Invalid value: {}: empty selector is invalid for deployment']
  创建后把 spec.selector 从 app=frontend 改成 app=backend:退出码 1;['The Deployment "d-fix" is invalid: spec.selector: Invalid value: {"matchLabels":{"app":"backend"}}: field is immutable']
  Service 不写 selector(空):不会去选 Pod,endpoints 由人手工管理;读出的 spec.selector=None
  NetworkPolicy 的 podSelector: {} 则是“选中命名空间里的全部 Pod”(同样是空选择器,含义相反)

Deployment 的 matchExpressions(app In [frontend,backend] 且 tier DoesNotExist)配模板标签 app: frontend 创建成功;选择器 app=backend 但模板标签是 app: frontend 被拒(`selector` does not match template `labels`);选择器写成 {} 被拒(empty selector is invalid for deployment);创建后把 spec.selector 改成 app=backend 被拒(field is immutable)。Service 不写 selector 就不会选 Pod;NetworkPolicy 里的 podSelector: {} 却是“选中命名空间里全部 Pod”——同样是空选择器,含义因资源而异。(实验中还踩到一个 YAML 坑:app: y 的 y 会被解析成布尔值。)

标签的语法

实测 · 本机执行输出
  值 63 个字符                    → 退出码 0
  值 64 个字符                    → 退出码 1;The ConfigMap "lab-test" is invalid: metadata.labels: Invalid value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": must be no more than 63 bytes
  值带空格                        → 退出码 1;The ConfigMap "lab-test" is invalid: metadata.labels: Invalid value: "a b": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '((
  值以 - 开头                     → 退出码 1;The ConfigMap "lab-test" is invalid: metadata.labels: Invalid value: "-ab": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '((
  值为空串                        → 退出码 0
  键带前缀 example.com/name       → 退出码 0
  键名部分 64 个字符                 → 退出码 1;The ConfigMap "lab-test" is invalid: metadata.labels: Invalid value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": name part must be no more than 63 bytes
  键前缀带大写 Example.com/name     → 退出码 1;The ConfigMap "lab-test" is invalid: metadata.labels: Invalid value: "Example.com/name": prefix part a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is 

值 63 个字符通过、64 个字符被拒(must be no more than 63 bytes);值带空格或以 - 开头被拒(要求空串,或字母数字开头结尾,中间可含 - _ .);空串允许;带前缀的键 example.com/name 通过;键名部分 64 个字符被拒;前缀写成大写 Example.com/name 被拒(前缀必须是小写的 RFC 1123 子域名)。

标签变了,归属立刻变

实测 · 本机执行输出
  Deployment web 3 个副本,Service web 的 endpoint 数 3
  给一个 Pod 加新标签 env=debug:pod/web-679886b487-8djjf labeled
  再改同一个键 env=other(不加 --overwrite):退出码 1;["error: 'env' already has a value (debug), and --overwrite is false"]
  加 --overwrite:pod/web-679886b487-8djjf labeled
  把 app 标签改成 web-quarantine:0.0 秒后 Service 的 endpoint 从 3 变成 2(Pod 被踢出 Service)
  Deployment 补了一个新 Pod:app=web 的 Pod 数 3;命名空间里总共 4 个 Pod;被改标签的那个还在运行(True),但已脱离 ReplicaSet 和 Service——这是“隔离故障 Pod 留着排查”的常用手法

Deployment web 3 个副本,Service web 有 3 个 endpoint。给一个 Pod 加标签 env=debug 成功;再改 env=other 不加 --overwrite 失败('env' already has a value (debug), and --overwrite is false)。把它的 app 标签改成 web-quarantine:0.1 秒后 Service 的 endpoint 从 3 变成 2;Deployment 补了一个新 Pod(app=web 的 Pod 仍是 3 个,命名空间里共 4 个);被改标签的那个还在运行,但脱离了 ReplicaSet 和 Service——隔离问题 Pod 留着排查的常用手法。

分步演示

标签与选择器
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);选择器语法实验用 ConfigMap(创建快,没有额外行为);控制器实验用 replicas: 0 的 Deployment 校验选择器规则;endpoint 数来自 EndpointSlice,0.2 秒轮询;每种情形各一次
    • 没有验证:set-based 选择器在 Service(只支持等值)中的限制;matchExpressions 的 Gt / Lt(仅用于节点亲和,不在这里);字段选择器(--field-selector)与标签选择器的区别;apps/v1beta 时期 selector 可变的历史;标签数量上限;ownerReferences 与选择器对“收养”的联合作用(见 k47)
    京ICP备2026067502号-1京公网安备11010502063487号