3.5 标签与标签选择器

标签是Kubernetes极具特色的功能之一。它是附加在Kubernetes任何资源对象之上的键值型数据,常用于标签选择器的匹配度检查,从而完成资源筛选。Kubernetes系统的部分基础功能的实现也要依赖标签和标签选择器,例如Service筛选并关联后端Pod对象,由ReplicaSet、StatefulSet和DaemonSet等控制器过滤并关联后端Pod对象等,从而提升用户的资源管理效率。

3.5.1 资源标签

标签可在资源创建时直接指定,也可随时按需添加在活动对象上。一个对象可拥有不止一个标签,而同一个标签也可添加至多个对象之上。在实践中,可以为资源附加多个不同维度的标签以实现灵活的资源分组管理功能,例如版本标签、环境标签、分层架构标签等,用于交叉标识同一个资源所属的不同版本、环境及架构层级等。下面是较为常用的标签。

▪版本标签:"release" : "stable","release" : "canary","release" : "beta"。

▪环境标签:"environment" : "dev","environment" : "qa","environment" : "prod"。

▪应用标签:"app" : "ui","app" : "as","app" : "pc","app" : "sc"。

▪架构层级标签:"tier" : "frontend","tier" : "backend","tier" : "cache"。

▪分区标签:"partition" : "customerA","partition" : "customerB"。

▪品控级别标签:"track" : "daily","track" : "weekly"。

标签中的键名称通常由“键前缀”和“键名”组成,其格式形如KEY_PREFIX/KEY_NAME,键前缀为可选部分。键名至多能使用63个字符,支持字母、数字、连接号(-)、下划线(_)、点号(.)等字符,且只能以字母或数字开头。而键前缀必须为DNS子域名格式,且不能超过253个字符。省略键前缀时,键将被视为用户的私有数据。由Kubernetes系统组件或第三方组件自动为用户资源添加的键必须使用键前缀,kubernetes.io/和k8s.io/前缀预留给了Kubernetes的核心组件使用,例如Node对象上常用的kubernetes.io/os、kubernetes.io/arch和kubernetes.io/hostname等。

标签的键值必须不能多于63个字符,键值要么为空,要么以字母或数字开头及结尾,且中间只能使用字母、数字、连接号(-)、下划线(_)或点号(.)等字符。

提示

在实践中,建议键名及键值能做到“见名知义”且尽可能保持简单。

创建资源时,可直接在其metadata中嵌套使用labels字段定义要附加的标签项。例如在下面的Namespace资源配置清单文件中,示例ns-with-labels.yaml中使用了两个标签,env=dev和app=eshop。


apiVersion: v1
kind: Namespace
metadata:
  name: eshop
  labels:
    app: eshop
    env: dev
spec:
  finalizers:
  - kubernetes

根据该配置清单创建出定义的Namespace对象之后,即可在kubectl get namespaces命令中使用--show-labels选项,以额外显示对象的标签信息。


~$ kubectl apply -f ns-with-labels.yaml 
namespace/eshop created
~$ kubectl get namespaces eshop --show-labels
NAME  STATUS   AGE   LABELS
demoapp   Active      11s   app=eshop,env=dev

标签较多时,在kubectl get命令上使用-L key1,key2,…选项可指定有特定键的标签信息。例如,仅显示eshop名称空间上的env和app标签:


~$ kubectl get namespaces eshop -L env,app
NAME    STATUS   AGE   ENV   APP
eshop       Active     89s    dev   eshop

kubectl label命令可直接管理活动对象的标签,以按需进行添加或修改等操作。例如为eshop名称空间添加release=beta标签:


~$ kubectl label namespaces/eshop release=beta
namespace/eshop labeled

不过,对于已经附带了指定键名的标签,使用kubectl label为其设定新的键值时需同时使用--overwrite命令,以强制覆盖原有键值。例如,将eshop名称空间的release标签值修改为canary:


~$ kubectl label namespaces/eshop release=canary --overwrite
namespace/eshop labeled

删除活动对象上的标签时同样要使用kubectl label命令,但仅需要指定标签名称并紧跟一个减号“–”,例如,下面的命令首先删除eshop名称空间中的env标签,而后显示其现有的所有标签:


~$ kubectl label namespaces/eshop env-
namespace/eshop labeled
~$ kubectl get namespaces eshop --show-labels 
NAME    STATUS   AGE     LABELS
eshop   Active   6m46s   app=eshop,release=beta

用户若期望对某标签下的资源集合执行某类操作,例如查看或删除等,需要先使用标签选择器挑选出符合条件的资源对象。

3.5.2 标签选择器

标签选择器用于表达标签的查询条件或选择标准,目前Kubernetes API支持两个选择器:基于等值关系(equality-based)的标签选项器与基于集合关系(set-based)的标签选择器。同时,在指定多个选择器时需要以逗号分隔,各选择器之间遵循逻辑“与”,即必须要满足所有条件,而且空值的选择器将不选择任何对象。

基于等值关系的标签选择器的可用操作符有=、==和!=,其中前两个意义相同,都表示“等值”关系,最后一个表示“不等”。例如env=dev和env!=prod都是基于等值关系的选择器。基于集合的标签选择器则根据标签名的一组值进行筛选,它支持in、notin和exists这3种操作符,例如tier in (frontend,backend)表示所有包含tier标签且其值为frontend或backend的资源对象。

kubectl get命令的“-l”选项能够指定使用标签选择器筛选目标资源,例如,如下命令显示标签release的值不等于beta,且标签app的值等于eshop的所有名称空间:


~$ kubectl get namespaces -l 'release!=beta,app=eshop'  -L app,release
NAME      STATUS      AGE   APP     RELEASE
eshop     Active      60m   eshop   canary

基于集合关系的标签选择器用于基于一组值进行过滤,它支持in、notin和exists 3种操作符,各操作符的使用格式及意义如下。

▪KEY in (VALUE1,VALUE2,…):指定键名的值存在于给定的列表中即满足条件。

▪KEY notin (VALUE1,VALUE2,…):指定键名的值不存在于给定列表中即满足条件。

▪KEY:所有存在此键名标签的资源。

▪!KEY:所有不存在此键名标签的资源。

例如,下面的命令可以过滤出标签键名release的值为beta或canary的所有Namespace对象:


~$ kubectl get namespaces -l 'release in (beta,canary)' -L release
NAME       STATUS     AGE   RELEASE
eshop      Active     63m   canary

再如,下面的命令可以列出集群中拥有node-role.kubernetes.io标签的各Node对象:


~$ kubectl get nodes -l 'node-role.kubernetes.io/master' -L kubernetes.io/hostname
NAME                     STATUS   ROLES    AGE   VERSION   HOSTNAME
k8s-master01.ilinux.io   Ready    master   25d   v1.17.3   k8s-master01.ilinux.io
k8s-master02.ilinux.io   Ready    master   25d   v1.17.3   k8s-master02.ilinux.io
k8s-master03.ilinux.io   Ready    master   25d   v1.17.3   k8s-master03.ilinux.io

注意

为了避免叹号(!)被shell解释器解析,必须要为此类表达式使用单引号。

此外,Kubernetes的诸多资源对象必须以标签选择器的方式关联到Pod资源对象,例如Service资源在spec字段中嵌套使用selector字段定义标签选择器,而Deployment与StatefulSet等资源在selector字段中通过matchLabels和matchExpressions构造复杂的标签选择机制。

▪matchLabels:直接给定键值对指定标签选择器。

▪matchExpressions:基于表达式指定的标签选择器列表,每个选择器形如{key: KEY_NAME, operator: OPERATOR, values: [VALUE1,VALUE2,…]},选择器列表间为“逻辑与”关系;使用In或NotIn操作符时,其values必须为非空的字符串列表,而使用Exists或DostNotExist时,其values必须为空。

下面的资源清单片段是一个示例,它同时定义了两类标签选择器。


selector:
  matchLabels:
    component: redis
  matchExpressions:
    - {key: tier, operator: In, values: [cache]}
    - {key: environment, operator: Exists, values:}

标签赋予了Kubernetes灵活操作资源对象的能力,它也是Service和Deployment等核心资源类型得以实现的基本前提。