3-8-标签和标签选择器

熊 0 阅读 容器

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

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

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

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等核心资源类型得以实现的基本前提。

3. 资源注释

除了标签之外 , Kubernetes的API对象还支持使用资源注解 (annotations)。类似于标签 , 注解也是键值型数据 , 不过它不能用作标签 , 也不能用于挑选API对象。

资源注解的核心目的是为资源提供 “元数据”信息 , 但注解的值不受字符数量的限制 , 它可大可小 , 可以是结构化或非结构化形式 , 也支持在标签中禁用其他字符。 资源注解可由用户手动添加 , 也可由工具程序自动附加并使用。 在Kubernetes的新版本(Alpha或Beta阶段)中计划为某资源引入新字段时常以注解方式提供 , 以避免字段名称变更、增删等变动给用户带去困扰 , 一旦确定使用这些新增字段 , 则将其引入资源规范中并淘汰 相关的注解信息。另外 , 为资源添加注解也可让其他用户快速了解资源的相关信息 , 例如创建者身份等。以下为常用的场景案例。

  • 由声明式配置(例如apply命令)管理的字段 : 将这些字段定义为注解 , 有助于识别由服务器或客户端设定的默认值、系统自动生成 的字段以及由自动伸缩系统生成的字段。

  • 构建、发行或镜像相关的信息 , 例如时间戳、发行ID、Git分支、PR号码、镜像哈希及仓库地址等。

  • 指向日志、监控、分析或审计仓库的指针。

  • 由客户端库或工具程序生成的用于调试目的的信息: 例如名称、版本、构建信息等。

  • 用户或工具程序的来源地信息 , 例如来自其他生态系统组件的 相关对象的URL。

  • 轻量化滚动升级工具的元数据 , 例如config及checkpoints。

  • 相关人员的电话号码等联系信息 , 或指向类似信息的可寻址的 目录条目 , 例如网站站点。

kubectl get -o yaml和kubectl describe命令均能显示资源的注解信息。例如 , 下面的命令打印出了节点对象k8s-master01.ilinux.io的注解信息:

~ $ kubectl get nodes k8s-master01.ilinux.io -o yaml     
apiVersion: v1 
kind: Node 
metadata: 
  annotations: 
    flannel.alpha.coreos.com/backend-data: '{"VtepMAC":"da:49:da:c7:8c:a1"}' 
    flannel.alpha.coreos.com/backend-type: vxlan 
    flannel.alpha.coreos.com/kube-subnet-manager: "true" 
    flannel.alpha.coreos.com/public-ip: 172.29.9.1 
    kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock 
    node.alpha.kubernetes.io/ttl: "0" 
    volumes.kubernetes.io/controller-managed-attach-detach: "true" 
    creationTimestamp: "2020-02-16T06:23:03Z" 
 ......

annotations可在资源创建时由metadata.annotations字段指定 , 也可随时按需在活动的资源上使用kubectl annotate命令进行添加。 例如 , 可以使用下面的命令为eshop名称空间添加注解:

~$ kubectl annotate namespaces/eshop ilinux.io/createdby='cluster admin' 
namespace/eshop annotated

删除活动对象上的注解时同样要使用kubectl annotate命令 , 但仅需指定注解键名并紧跟一个减号“–”即可。例如 , 下面的命令会删除eshop名称空间中的ilinux.io/created-by注解:

~$ kubectl annotate namespaces/eshop ilinux.io/created-by- 
namespace/eshop annotated

有些应用程序还支持通过注解信息进行高级配置 , 例如ingress nginx提供了众多专用的注解 , 以允许用户向应用注入指定的高级配 置。在下面配置清单中的Ingress资源示例中 , 注解 nginx.org/server-snippets还使用了多行值的格式。

apiVersion: networking.k8s.io/v1beta1 
kind: Ingress 
metadata: 
  name: cafe-ingress-with-annotations 
  annotations: 
    nginx.org/proxy-connect-timeout: "30s" 
    nginx.org/proxy-read-timeout: "20s" 
    nginx.org/client-max-body-size: "4m" 
    nginx.org/server-snippets: | 
      location / { 
        return 302 /somewhere; 
      } 
spec: 
  rules: 
  …

Nginx的Ingress Controller对应的Pod对象在读取Ingress配置清单时会将注解中给定的配置转换为Nginx程序的配置信息,并由相应的进程加载使用。