云原生系列Kubernetes篇 标签和注解

本文来自正在规划的Go语言&云原生自我提升系列,欢迎关注后续文章。

Kubernetes可随着应用大小和复杂度的扩展而扩展。标签和注解是Kubernetes中的基本概念,可以让人类的想法对应用进行分组。我们可以组织、标记以及交叉索引所有表示应用中分组的资源。

标签是打在Kubernetes对象比如Pod和副本集上的键值对。可以是任意名称,对于关联识别Kubernetes对象信息非常有用。标签为对象分组提供了基础。

而注解则提供了类似标签的存储机制:用于存储工具和库可使用的非标识信息的键值对。不同于标签的是,注解不是用来查询、过滤或是区分Pod的。

标签

标签用于标识对象的元数据。用于对对象分组、浏览和操作。使用标签源自Google运行大型复杂应用的经验。来自这些经验的一些总结:

  • 生产环境无单体。在部署软件时,通常会启动单实例。但随着应用逐渐成熟,这些单体通常会变多,成本一组对象。因此Kubernetes处理一组对象而不是单个实例。
  • 系统的等级对很多用户总会捉襟见肘。此外,用户分组和等级会随时间发生变化。比如,用户一开始认为所有应用由多个服务组成。但一段时间后发现同一个服务可能由多应用共享。Kubernetes的标签足够灵活,远不止可适用这些场景。

有关站点可靠性请参见Betsy Beyer等人所写的站点可靠性工程一书(也就是大名鼎鼎的Google SRE)。

标签语法简单。就是键值对,键和值都是字符串。标签的键可分为两部分:可选前缀和名称,由斜杠分开。如定义了前缀,必须是不超过253个字符的DNS子域名。必须要有键名称,最大长度为63个字符。名称必须以字母数字字符开头和结束,允许在中间使用横杠(-)、下划线(_)和点(.) 。

标签的值是最长63个字符的字符串。标签的值与键规则相同。表6-1展示了一些有限的标签键和值。

表6-1 标签示例

[table id=100 /]

在标签和注解中使用域名时,应该以某种方式结合具体的实体。例如,项目中可能会定义一组标签来标识应用部署的不用阶段,如待发布、金丝雀测试和生产等。或是云服务商可能会定义厂商相关的注解来扩展Kubernetes对象开启相应服务特性。

应用标签

这里我们使用一些标签创建一些部署(一种创建一组Pod的方式)。共两个应用(alpacabandicoot),环境和版本各异。

首先,创建一个部署alpaca-prod,设置verappenv 标签:

$ kubectl create deployment alpaca-prod --image=gcr.io/kuar-demo/kuard-amd64:blue --replicas=2
$ kubectl label pods -l 'app=alpaca-prod' --overwrite ver=1 app=alpaca env=prod

注:kubectl run已弃用了--replicas参数,所以没有法直接使用kubectl run

接着,创建 一个部署alpaca-test,并将verappenv标签设置为相应值:

$ kubectl create deployment alpaca-test --image=gcr.io/kuar-demo/kuard-amd64:green --replicas=1
$ kubectl label deployment pods -l 'app=alpaca-test' --overwrite ver=2 app=alpaca env=test

最后为bandicoot创建两个部署。将环境分别命名为prodstaging

$ kubectl create deployment bandicoot-prod --image=gcr.io/kuar-demo/kuard-amd64:green --replicas=2
$ kubectl label pods -l 'app=bandicoot-prod' --overwrite ver=2 app=bandicoot env=prod
$ kubectl create deployment bandicoot-staging --image=gcr.io/kuar-demo/kuard-amd64:green --replicas=1
$ kubectl label pods -l 'app=bandicoot-staging' --overwrite ver=2 app=bandicoot env=staging

此时,应该有4个部署,alpaca-prodalpaca-testbandicoot-prodbandicoot-staging

$ kubectl get deployments --show-labels

NAME                ... LABELS
alpaca-prod         ... app=alpaca,env=prod,ver=1
alpaca-test         ... app=alpaca,env=test,ver=2
bandicoot-prod      ... app=bandicoot,env=prod,ver=2
bandicoot-staging   ... app=bandicoot,env=staging,ver=2

可根据标签可视化为如下的文氏图:

图6-1 应用于部署的标签可视化显示

图6-1 应用于部署的标签可视化显示

修改标签

创建好对象后还可以应用或更新标签:

$ kubectl label deployments alpaca-test "canary=true"

警告:以上示例中,kubectl labe命令只会修改部署自身的标签,而不会影响其它由部署创建的对象,比如副本集和Pod。如需修改它们,需要更改部署中内嵌的模板(参见第10章)。

还可以对kubectl get使用-L参数按列显示标签值:

$ kubectl get deployments -L canary

NAME                DESIRED   CURRENT   ... CANARY
alpaca-prod         2         2         ... 
alpaca-test         1         1         ... true
bandicoot-prod      2         2         ... 
bandicoot-staging   1         1         ...

可以通过减号后缀删除某个标签:

$ kubectl label deployments alpaca-test "canary-"

标签选择器

标签选择器用于通过一组标签过滤Kubernetes对象。选择器使用一种简单的布尔表达式。可供终端用户(通kubectl这样的工具)或是各类对象(比如副本集如何与Pod关联)使用。

每个(通过副本集的)部署使用部署中内嵌模板指定的标签创建一组Pod。由kubectl run命令配置。

运行kubectl get pods命令会返回集群中当前运行的所有Pod。我们一共有位于三种环境的6个kuard Pods:

$ kubectl get pods --show-labels

NAME                              ... LABELS
alpaca-prod-3408831585-4nzfb      ... app=alpaca,env=prod,ver=1,...
alpaca-prod-3408831585-kga0a      ... app=alpaca,env=prod,ver=1,...
alpaca-test-1004512375-3r1m5      ... app=alpaca,env=test,ver=2,...
bandicoot-prod-373860099-0t1gp    ... app=bandicoot,env=prod,ver=2,...
bandicoot-prod-373860099-k2wcf    ... app=bandicoot,env=prod,ver=2,...
bandicoot-staging-1839769971-3ndv ... app=bandicoot,env=staging,ver=2,...

注:读者可能会发现之前没见过的标签:pod-template-hash。这个标签由部署添加,用于跟踪哪个Pod是由哪个模板版本所生成。这样可以由部署清晰地管理更新,这部分内容会在第10章中进行讲解。

如果希望只列出标签ver2的Pod,可以使用--selector参数:

$ kubectl get pods --selector="ver=2"

NAME                                 READY     STATUS    RESTARTS   AGE
alpaca-test-1004512375-3r1m5         1/1       Running   0          3m
bandicoot-prod-373860099-0t1gp       1/1       Running   0          3m
bandicoot-prod-373860099-k2wcf       1/1       Running   0          3m
bandicoot-staging-1839769971-3ndv5   1/1       Running   0          3m

如果指定了由逗号分隔的两个选择器,只有同时满足两个条件的对象会返回。这是一个逻辑与运算:

$ kubectl get pods --selector="app=bandicoot,ver=2"

NAME                                 READY     STATUS    RESTARTS   AGE
bandicoot-prod-373860099-0t1gp       1/1       Running   0          4m
bandicoot-prod-373860099-k2wcf       1/1       Running   0          4m
bandicoot-staging-1839769971-3ndv5   1/1       Running   0          4m

也可查询标签是否在一组值之中。下面查看所有app 标签为alpacabandicoot 的Pod(返回所有这6个Pod):

$ kubectl get pods --selector="app in (alpaca,bandicoot)"

NAME                                 READY     STATUS    RESTARTS   AGE
alpaca-prod-3408831585-4nzfb         1/1       Running   0          6m
alpaca-prod-3408831585-kga0a         1/1       Running   0          6m
alpaca-test-1004512375-3r1m5         1/1       Running   0          6m
bandicoot-prod-373860099-0t1gp       1/1       Running   0          6m
bandicoot-prod-373860099-k2wcf       1/1       Running   0          6m
bandicoot-staging-1839769971-3ndv5   1/1       Running   0          6m

最后,我们可以查询是否设置了某个标签。下面我们查找设置过canary标签值的部署:

$ kubectl get deployments --selector="canary"

NAME          DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
alpaca-test   1         1         1            1           7m

以上这些还有取反的版本,参见表6-2。

表6-2 选择器运算符

[table id=101 /]

例如,查询某个键未设置的命令如下,此处为canary

$ kubectl get deployments --selector='!canary'

可以合并使用正向和取反运算符:

$ kubectl get pods -l 'ver=2,!canary'

API对象中的标签选择器

Kubernetes对象使用标签选择器来指代一组其它Kubernetes对象。不同于前面小节中的普通字符串,我们使用一套解析结构。

出于历史原因(Kubernetes保持API的兼容),存在两种形式。大部分对象支持更新、更强大的一组选择器运算符。app=alpaca,ver in (1, 2)选择器可转化成:

selector:
  matchLabels:
    app: alpaca
  matchExpressions:
    - {key: ver, operator: In, values: [1, 2]}

上例使用紧凑的YAML语法。它是matchExpressions列表中的一个包含三项的字典。最后一项 (values)的值为包含两项的列表。所有这些内容都通过逻辑与进行运算。表示!=运算符的唯一方式是将其转换为带单个值的NotIn 表达式。

选择器更老一些的形式(用于ReplicationController和服务中)仅支持= 运算符。= 运算选择所有配置键值对组的对象。app=alpaca,ver=1选择器可表示为:

selector:
  app: alpaca
  ver: 1

Kubernetes架构中的标签

标签除了可供用户组织自己的基础设置,还对关联各个Kubernetes对象起着重要的作用。Kubernetes是刻意保持解耦的系统。不存在等级,所有组件都独立运行。但在很多情况下,对象需要相互关联,这些关联通过标签和标签选择器定义。

例如,副本集,用于创建和维护Pod的多个副本,查找其通过选择器管理的Pod。类似地,服务负载均衡通过选择器查询查找发送流量的Pod。在创建Pod时,可使用节点选择器来标识出一组可供其调度的节点。在希望在集群中限制网络流量时,可使用网络策略配合具体的标签来分别出允许和不允许通讯的Pod。

标签是将Kubernetes应用组合在一起的强大的万能胶水。虽然应用可能一开始只有一组简单的标签和查询,随着业务增长它会变得更多更复杂。

注解

注解用于存储Kubernetes更多的元信息,元信息的唯一目的是辅助工具和库。它是其它程序通过API存储一些复杂对象数据驱动Kubernetes 的一种方式。注解可用于工具本身或是在外部系统之间传递配置信息。

标签的用途是标识和分组对象,而注解用于提供对象来源、如何使用及其策略的额外信息。有重叠的部分,何时使用注解、何时使用标签是个人习惯问题。在不确定时,以注解向对象添加信息,在发现需要在选择器中使用它时再将其修改为标签。

注解用于:

  • 记录对象最近更新的原因
  • 一个专项调度策略和另一个专项调度的通讯
  • 上一个工具更新资源的扩展数据以及是如何更新的(用于监测其它工具的变化及进行智能合并)
  • 添加不适宜标签的构建、发布或镜像信息(包括Git哈希、时间戳、pull请求单号等)
  • 部署对象记录其管理的滚动发布的副本集
  • 提供增强视觉品质或UI可用性的附加信息。登录,对象可包含图标的链接(或base64编码的图标)
  • Kubernetes原型alpha版本功能(不创建一级API字体,而是将功能的参数编码放到注解中)

注解用在Kubernetes中的各处,主要用途是滚动部署。在滚动部署期间,注释用于追踪滚动发布状态并在需要回滚到上一个状态的部署时提供回滚所需信息。

避免把 Kubernetes API服务端用作通用数据库。注解对存储与特定资源调度关联的多个小块数据很有益处。如果希望在Kubernetes中存储的数据 并没有明确的关联对象,考虑将数据存储到更合适的数据库中。

注解的键与标签的键格式相同。但因其更常用于在工具间传输信息,键中的命名空间就显得更为重要。举几个键的例子:deployment.kubernetes.io/revisionkubernetes.io/change-cause

注解中的值为任意形式的字符串。虽然有很强的灵活性,允许用户存储任意数据,但因为是任意文本,并没有做格式校验。例如,经常会将JSON文档编码为字符串存到注解中。需要注意Kubernetes 服务端并不会知道注解的值需要用什么格式。如果使用注解传递或存储数据,并不能保证数据的有效性。这会让错误的追踪变得更困难。

注解在Kubernetes对象的通用metadata 版块中定义:

...
metadata:
  annotations:
    example.com/icon-url: "https://example.com/icon.png"
...

警告:注解用起来很方便,具有强大的松耦合性,但谨慎使用避免出现混乱的数据。

清理

清理本文一开始创建的部署非常简单:

$ kubectl delete deployments --all

如果希望进行限定,可使用--selector参数选择要删除的部署。

小结

标签可用于标识或是分组Kubernetes集群中的对象。也可用于选择器查询实现对象,如Pod的灵活运行时分组。

注解提供了自动化工具和客户端库使用的具有对象作用域的键值元数据。也可用于存储外部工具如第三方调度工具或监控工具使用的配置数据。

标签和注解对于理解Kubernetes集群中的重要组成部分如何协作保障处于所需的集群状态非常关键。恰当的使用可以解锁Kubernetes的强大能力,也为自动化工具和部署工作流提供了起点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容