LabHub
学习 学习路径 课程

CRD 与 Operator

从一份 CR 生成下层资源与状态

在 LabHub 中继续学习

目标

以一份 CR 作为输入创建下层资源,再把结果写回 status,亲手完成让一行 kubectl get 就能说明部署状态的结构。

为什么重要

把 CR 作为部署接口时,必须遵守四项纪律。**第一,spec 由用户写,status 由控制器写。**控制器修改 spec 会让 Git 仓库与集群产生差异,下一次同步会将其抹去。**第二,status 必须通过独立路径写入。**启用子资源后,普通 update 会静默忽略 status,表现为“明明写了却没有生效”。**第三,为子资源添加 owner reference。**删除父对象时,垃圾回收器会自动清理子对象;控制器只需管理“自己创建的对象”,清理逻辑更简单。连接依据不是名称,而是 uid:删除同名父对象再重建后,uid 会改变,指向旧 uid 的子对象会立即被回收。**第四,用 observedGeneration 显示时间差。**若它小于 metadata.generation,表示“status 仍基于旧 spec”。没有这组值,用户无法判断 status 是否可信。

步骤

开始前准备:每次实验都会创建新的实验 Pod,因此上一实验的集群状态不会保留。如果 kubectl get crd webservices.apps.labhub.io 为空,请重新编写并应用 CRD,同时执行 kubectl create ns crd-lab。本实验需要 v1 的 additionalPrinterColumns(Image/Replicas/Tier/Age)、subresources.statussubresources.scale.spec.replicas/.status.replicas/.status.selector),以及 properties.status 下的 replicasselectorobservedGenerationconditions 定义。缺少 status 模式时,即使 patch,内容也会被 pruning 裁掉。

  1. /root/crd/deploy/minimal.yaml 中编写 WebService:metadata.name: minimal,命名空间为 crd-lab,且只包含 spec.image: nginx:1.27,然后应用。不要填写 spec.replicas。保存后的对象必须显示 spec.replicas 为 1。
  2. /root/crd/deploy/storefront.yaml 中编写并应用 WebService,包含 metadata.name: storefrontmetadata.labels.tier: prodspec.image: nginx:1.27spec.replicas: 4spec.tier: prod
  3. crd-lab 中创建 ConfigMap storefront-config。在 metadata.ownerReferences[0] 中填入 apiVersion: apps.labhub.io/v1kind: WebServicename: storefrontcontroller: trueuid 必须使用 kubectl get webservice storefront -n crd-lab -o jsonpath='{.metadata.uid}' 查询到的真实值。
  4. storefront 的 status 中写入 replicas: 4selector: app=storefront。必须使用带 --subresource=status 的 patch,并把完整命令行保存到 /root/crd/deploy/out/status-patch.txt
  5. 在同一 status 中加入 conditionstype: Readystatus: "True"reason: AllReplicasReadymessage 可自由填写,lastTransitionTime 使用 date -u +%Y-%m-%dT%H:%M:%SZ 格式的 RFC3339 时间。同时把 status.observedGeneration 写成与 metadata.generation 相同的值。
  6. /opt/lab/fixtures/crd/sample-cr.yaml 应用到 crd-lab,增加 sample(此时共有 3 个 WebService)。然后运行 kubectl label webservice minimal -n crd-lab tier=dev 添加标签,把 kubectl get webservice -n crd-lab -l tier=prod 的输出保存到 /root/crd/deploy/out/selected.txt。文件中必须有 storefront、没有 minimal,且 tier=prod 精确匹配一个对象。
  7. kubectl get webservice -n crd-lab -o custom-columns=NAME:.metadata.name,IMAGE:.spec.image,TIER:.spec.tier 的输出保存到 /root/crd/deploy/out/columns.txt。应包含一行表头与至少三行资源,总计至少四行。
  8. crd-lab 中创建 ConfigMap storefront-desireddata.imagedata.replicasdata.tier 三个键的值,必须以字符串形式与从 storefrontspec 读取的值完全相同,并按第 3 步相同方式把 storefront 设为所有者。完成后,status.observedGeneration 仍必须等于 metadata.generation

参考

使用最小 spec 创建 CR

/root/crd/deploy/minimal.yaml 中编写 WebService:metadata.name: minimal,命名空间为 crd-lab,且只包含 spec.image: nginx:1.27,然后应用。不要填写 spec.replicas。保存后的对象必须显示 spec.replicas 为 1。

只填写一个必填字段。其他字段应留空,否则无法确认是否由默认值填充。

创建填写完整 spec 的 CR

/root/crd/deploy/storefront.yaml 中编写并应用 WebService,包含 metadata.name: storefrontmetadata.labels.tier: prodspec.image: nginx:1.27spec.replicas: 4spec.tier: prod

spec 值与 metadata 标签位于不同位置。前者是控制器读取的意图,后者是供选择器检索的索引,两者都需要。

通过 owner reference 绑定子对象

crd-lab 中创建 ConfigMap storefront-config。在 metadata.ownerReferences[0] 中填入 apiVersion: apps.labhub.io/v1kind: WebServicename: storefrontcontroller: trueuid 必须使用 kubectl get webservice storefront -n crd-lab -o jsonpath='{.metadata.uid}' 查询到的真实值。

owner reference 通过 uid 而不是名称连接。先查询父对象 uid,再填入该值。apiVersion 要同时包含组和版本,还需要表示主控制器的 bool 字段。

向 status 子资源写入观测值

storefront 的 status 中写入 replicas: 4selector: app=storefront。必须使用带 --subresource=status 的 patch,并把完整命令行保存到 /root/crd/deploy/out/status-patch.txt

普通 patch 会忽略 status。必须指定 status 专用路径,并把包含该选项的命令本身保存到文件。selector 是 키=값 形式的字符串。

填写标准 conditions 与 observedGeneration

在同一 status 中加入 conditionstype: Readystatus: "True"reason: AllReplicasReadymessage 可自由填写,lastTransitionTime 使用 date -u +%Y-%m-%dT%H:%M:%SZ 格式的 RFC3339 时间。同时把 status.observedGeneration 写成与 metadata.generation 相同的值。

Ready 条件同时需要机器读取的原因代码和人类读取的说明。时间必须使用 RFC3339 格式,已处理的 generation 必须与 metadata 中的值相同。

使用标签选择器筛选 CR

/opt/lab/fixtures/crd/sample-cr.yaml 应用到 crd-lab,增加 sample(此时共有 3 个 WebService)。然后运行 kubectl label webservice minimal -n crd-lab tier=dev 添加标签,把 kubectl get webservice -n crd-lab -l tier=prod 的输出保存到 /root/crd/deploy/out/selected.txt。文件中必须有 storefront、没有 minimal,且 tier=prod 精确匹配一个对象。

选择器匹配 metadata 标签,而不是 spec 值。请给其他 CR 添加不同值,确保 prod 精确匹配一个对象。

使用 custom-columns 提取所需字段

kubectl get webservice -n crd-lab -o custom-columns=NAME:.metadata.name,IMAGE:.spec.image,TIER:.spec.tier 的输出保存到 /root/crd/deploy/out/columns.txt。应包含一行表头与至少三行资源,总计至少四行。

除了 CRD 定义的列,也可以在查询时直接指定列。用逗号连接 머리글:JSON경로

根据 CR spec 创建期望状态对象

crd-lab 中创建 ConfigMap storefront-desireddata.imagedata.replicasdata.tier 三个键的值,必须以字符串形式与从 storefrontspec 读取的值完全相同,并按第 3 步相同方式把 storefront 设为所有者。完成后,status.observedGeneration 仍必须等于 metadata.generation

不要手工抄写值,应从 CR 读取后原样填入。三个值都必须与 CR 完全一致,也要建立父对象连接。如果修改了 spec,还应重新对齐已处理的 generation。