跳到主要内容
08:44:02
🔅🔆

标签和选择算符

标签(Labels) 是附加到 Kubernetes 对象(比如 Pod)上的键值对,旨在指定对用户有意义且相关的对象标识属性,但不直接对核心系统有语义含义。标签可以用来组织和选择对象的子集。标签可以在创建时附加到对象,随后可以随时添加和修改。每个对象都可以定义一组键/值标签,每个键对于给定对象必须是唯一的。

"metadata": {
"labels": {
"key1" : "value1",
"key2" : "value2"
}
}

标签能够支持高效的查询和监听(watch)操作,对于用户界面和命令行是很理想的。应使用注解记录非识别信息。

官方文档参考​

文档链接
标签和选择算符(中文)https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/labels/
Labels and Selectors(英文,内容补充参考)https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/

动机​

标签使用户能够以松散耦合的方式将他们自己的组织结构映射到系统对象,而无需客户端存储这些映射。

服务部署和批处理流水线通常是多维实体(例如多个分区或部署、多个发行序列、多个层,每层多个微服务)。管理通常需要交叉操作,这打破了严格的层次表示的封装,特别是由基础设施而不是用户确定的严格层次结构。

常见示例标签:

维度示例
发布轨道"release" : "stable"、"release" : "canary"
环境"environment" : "dev"、"environment" : "qa"、"environment" : "production"
层级"tier" : "frontend"、"tier" : "backend"、"tier" : "cache"
分区"partition" : "customerA"、"partition" : "customerB"
跟踪"track" : "daily"、"track" : "weekly"

这些只是常用标签的例子,你可以任意制定自己的约定。但请记住,标签的 Key 对于给定对象必须是唯一的。

语法和字符集​

标签是键值对。有效的标签键有两个段:可选的前缀和名称,用斜杠(/)分隔。

组成部分规则
名称段(必需)小于等于 63 个字符,以字母数字([a-z0-9A-Z])开头和结尾,中间可包含破折号(-)、下划线(_)、点(.)和字母数字
前缀(可选)必须是 DNS 子域:由点(.)分隔的一系列 DNS 标签,总长不超过 253 个字符,后跟斜杠(/)
有效标签值63 个字符或更少(可以为空);除非为空,必须以字母数字开头和结尾;可包含 -、_、. 和字母数字

如果省略前缀,则假定标签键对用户是私有的。向最终用户对象添加标签的自动系统组件(例如 kube-scheduler、kube-controller-manager、kube-apiserver、kubectl 或其他第三方自动化工具)必须指定前缀。

保留前缀不要乱用

kubernetes.io/ 和 k8s.io/ 前缀是为 Kubernetes 核心组件保留的,业务自定义标签绝对不要使用这两个前缀。

例如,下面是一个具有 environment: production 和 app: nginx 两个标签的 Pod 的清单:

apiVersion: v1
kind: Pod
metadata:
name: metadata-demo
labels:
environment: production # 环境标签
app: nginx # 应用名标签
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

标签选择算符​

与名称和 UID 不同,标签不支持唯一性——通常我们希望许多对象携带相同的标签。通过标签选择算符(Label Selector),客户端/用户可以识别一组对象。标签选择算符是 Kubernetes 中的核心分组原语。

API 目前支持两种类型的选择算符:基于等值的和基于集合的。标签选择算符可以由逗号分隔的多个需求组成;在多个需求的情况下必须全部满足,因此逗号分隔符充当逻辑与(&&)运算符。

没有"或"操作符

对于基于等值的和基于集合的条件而言,不存在逻辑或(||)操作符。要确保过滤语句按合适的方式组织。

选择算符重叠冲突

对于某些 API 类别(例如 ReplicaSet)而言,两个实例的标签选择算符不得在命名空间内重叠,否则它们的控制器将互相冲突,无法确定应该存在的副本个数。

基于等值的需求​

基于等值或基于不等值的需求允许按标签键和值进行过滤。匹配对象必须满足所有指定的标签约束,尽管它们也可能具有其他标签。

运算符含义
= / ==相等(两者是同义词)
!=不相等(包括不存在该键的情况)

例如:

environment = production
tier != frontend

前者选择所有键名为 environment 且值为 production 的资源;后者选择所有键名为 tier 且值不等于 frontend 的资源,以及所有没有 tier 键标签的资源。可以用逗号运算符过滤 production 环境中的非 frontend 层资源:environment=production,tier!=frontend。

一种常见使用场景是 Pod 指定节点选择标准。下面的示例 Pod 选择存在 accelerator 标签且值为 nvidia-tesla-p100 的节点:

apiVersion: v1
kind: Pod
metadata:
name: cuda-test
spec:
containers:
- name: cuda-vector-add
image: "registry.k8s.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1
nodeSelector: # 通过标签选择调度节点
accelerator: nvidia-tesla-p100

基于集合的需求​

基于集合的标签需求允许你通过一组值来过滤键。支持三种操作符:in、notin 和 exists(只可以用在键标识符上)。例如:

environment in (production, qa)
tier notin (frontend, backend)
partition
!partition
示例含义
environment in (production, qa)选择所有键等于 environment 且值等于 production 或 qa 的资源
tier notin (frontend, backend)选择所有键等于 tier 且值不等于 frontend 或 backend 的资源,以及所有没有 tier 键的资源
partition选择所有包含 partition 标签的资源(不校验值)
!partition选择所有没有 partition 标签的资源(不校验值)

类似地,逗号分隔符充当与运算符。例如使用 partition, environment notin (qa) 来过滤"有 partition 键(无论其值为何)且 environment 不同于 qa"的资源。

基于集合的需求是基于等值需求的一般形式:environment=production 等同于 environment in (production),!= 与 notin 也是类似的。两种需求可以混合使用,例如:partition in (customerA, customerB),environment!=qa。

API​

LIST 和 WATCH 过滤​

对于 list 和 watch 操作,你可以指定标签选择算符过滤返回的对象集,使用查询参数指定过滤条件。两种需求都是允许的(这里显示它们出现在 URL 查询字符串中的形式):

  • 基于等值的需求:?labelSelector=environment%3Dproduction,tier%3Dfrontend
  • 基于集合的需求:?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29

使用 kubectl 定位 API 服务器时,基于等值的标签选择算符可以这么写:

kubectl get pods -l environment=production,tier=frontend

或者使用基于集合的需求:

kubectl get pods -l 'environment in (production),tier in (frontend)'

基于集合的需求更有表达力,例如实现值的或操作:

kubectl get pods -l 'environment in (production, qa)'

或者通过 notin 运算符限制不匹配:

kubectl get pods -l 'environment,environment notin (frontend)'

在 API 对象中设置引用​

一些 Kubernetes 对象,例如 Service 和 ReplicationController,也使用标签选择算符去指定其他资源的集合(例如 Pod)。

Service 和 ReplicationController​

一个 Service 指向的一组 Pod 由标签选择算符定义;一个 ReplicationController 应该管理的 Pod 集合同样由标签选择算符定义。这两个对象的标签选择算符都是在 json 或 yaml 文件中使用映射定义的,只支持基于等值需求的选择算符:

selector:
component: redis # 等价于 component=redis 或 component in (redis)

支持基于集合需求的资源​

比较新的资源,例如 Job、Deployment、ReplicaSet 和 DaemonSet,也支持基于集合的需求:

selector:
matchLabels:
component: redis # 等值匹配
matchExpressions:
- {key: tier, operator: In, values: [cache]} # tier In (cache)
- {key: environment, operator: NotIn, values: [dev]} # environment NotIn (dev)
字段说明
matchLabels由 {key,value} 对组成的映射;单个 {key,value} 等同于 matchExpressions 中 operator: In 且 values 仅含该值的元素
matchExpressionsPod 选择算符需求列表;有效运算符包括 In、NotIn、Exists 和 DoesNotExist;In 和 NotIn 的值必须非空

来自 matchLabels 和 matchExpressions 的所有要求按逻辑与组合——必须全部满足才能匹配。

matchLabels 与 matchExpressions 可以混用

两者是"与"关系。简单场景用 matchLabels 即可,需要 In/NotIn/Exists/DoesNotExist 语义时用 matchExpressions。

选择节点集​

通过标签进行选择的一个用例是确定节点集,方便 Pod 调度(参见"选择节点"相关文档,即上文 nodeSelector 示例)。

有效地使用标签​

许多情况下应使用多个标签来区分不同集合。例如,不同应用为 app 标签设置不同的值;而类似 guestbook 这样的多层应用,还需要区分每一层。

app 标签方便手动查询和简单命令行操作;app.kubernetes.io/name 标签遵循 Kubernetes 推荐的标签约定,更适合工具和自动化。

前端可能带有以下标签:

labels:
app: guestbook
app.kubernetes.io/name: guestbook
tier: frontend

Redis 的主从节点会有不同的 tier 标签,甚至还有一个额外的 role 标签:

labels:
app: guestbook
app.kubernetes.io/name: guestbook
tier: backend
role: master

以及:

labels:
app: guestbook
app.kubernetes.io/name: guestbook
tier: backend
role: replica

标签使得我们能够按照所指定的任何维度对资源进行切片和切块:

kubectl apply -f examples/guestbook/all-in-one/guestbook-all-in-one.yaml
kubectl get pods -Lapp -Ltier -Lrole # -L 参数将标签值显示为额外列
NAME READY STATUS RESTARTS AGE APP TIER ROLE
guestbook-fe-4nlpb 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-ght6d 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-jpy62 1/1 Running 0 1m guestbook frontend <none>
guestbook-redis-master-5pg3b 1/1 Running 0 1m guestbook backend master
guestbook-redis-replica-2q2yf 1/1 Running 0 1m guestbook backend replica
guestbook-redis-replica-qgazl 1/1 Running 0 1m guestbook backend replica
my-nginx-divi2 1/1 Running 0 29m nginx <none> <none>
my-nginx-o0ef1 1/1 Running 0 29m nginx <none> <none>
kubectl get pods -lapp=guestbook,role=replica # 组合过滤
NAME READY STATUS RESTARTS AGE
guestbook-redis-replica-2q2yf 1/1 Running 0 3m
guestbook-redis-replica-qgazl 1/1 Running 0 3m

更新标签​

有时需要在创建新资源之前对现有的 Pod 和其它资源重新打标签,这可以用 kubectl label 完成。例如,将所有 NGINX Pod 标记为前端层:

kubectl label pods -l app=nginx tier=fe
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
pod/my-nginx-2035384211-u3t6x labeled

该命令先用 "app=nginx" 过滤所有 Pod,然后用 "tier=fe" 标记它们。查看刚设置标签的 Pod:

kubectl get pods -l app=nginx -L tier # -L 显示 tier 标签列
NAME READY STATUS RESTARTS AGE TIER
my-nginx-2035384211-j5fhi 1/1 Running 0 23m fe
my-nginx-2035384211-u2c7e 1/1 Running 0 23m fe
my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe

我的总结与避坑清单​

  1. 标签是"标识 + 选择"用的,非识别信息(大文本、结构化数据)应记在注解里,不要塞进标签值(标签值最长 63 字符且有字符限制)。
  2. 标签键在同一对象内必须唯一;键名段最长 63 字符,前缀(DNS 子域)总长最长 253 字符,kubernetes.io/ 与 k8s.io/ 是保留前缀。
  3. Service 与 ReplicationController 的 selector 只支持基于等值的匹配;需要 In/NotIn/Exists/DoesNotExist 时要用 matchLabels + matchExpressions(仅 Deployment、ReplicaSet、DaemonSet、Job 等较新资源支持)。
  4. 标签选择算符没有逻辑或(||),逗号永远是"与";需要"值或"语义时用 in 表达,如 environment in (production, qa)。
  5. 同一命名空间内两个 ReplicaSet 的 selector 不能重叠,否则控制器互相冲突、副本数无法确定。
  6. 修改 Service 的 selector 时要小心:selector 一变,Service 立刻切换到新的后端 Pod 集合,可能引发流量丢失。
  7. kubectl label 更新已有标签时,如果键已存在且未加 --overwrite,会报错拒绝覆盖;批量改标签前先 -l 过滤确认范围。
  8. 推荐给每个工作负载同时打上简写的 app/tier 标签和 app.kubernetes.io/name 系列标签:前者方便人肉查询,后者供 Helm 等工具使用。
  9. kubectl get pods -l 'environment in (production, qa)' 这类含空格/括号的选择算符要加引号,否则 shell 会拆词报错。
  10. 空选择算符或未指定选择算符的语义取决于上下文——某些 API 类别里"空 selector"意味着匹配所有对象(例如 Service),写控制器逻辑时务必查清对应 API 的约定。
🛡️本站已安全运行2334天23时18分58秒
Bottom GIF
Top GIF