CR 既是部署的输入,也是状态报告
一句话总结
CR在一个对象中包含用户想要的东西的写入位置(spec)和系统反馈观察到的位置(status)。将这两个混合在一起的瞬间,部署就无法追踪了。
为什么需要这个?
考虑一下回答“这个服务现在运行良好吗?”的问题的方法。如果只使用Helm,就看发布列表,找到该发布创建的Deployment,找到该Deployment的ReplicaSet,然后计算板数。工具只告诉“安装命令成功”,之后的状态需要人组装。
CR将该组装带入对象中。用户spec写下意图,控制器是status写下观察结果。 那么kubectl get webservice一行即成为分配状态仪表板。但是,为了实现这种结构,需要纪律。
怎么行动
**规则1 — spec是用户,status是控制器。**控制器在spec中输入值的瞬间,GitOps存储库和群集就开始不一致。只有群集中出现用户提交的配置文件中没有的值,下次同步会删除它。所以status必须用单独的路径。
잘못됨: spec 과 status 를 한 번에 update -> status 서브리소스가 켜져 있으면 status 는 무시됨
올바름: status 만 서브리소스 경로로 갱신
纪律2——写状态,而不是命令。spec.restartNow: true相同的字段是反模式。一旦执行一次,该值就变得毫无意义,也不可以追踪是谁什么时候关闭的。相反spec.version伊娜spec.paused用具有持续意义的值来表达。这样调整循环无论什么时候再次运行都会做出同样的判断。
纪律3 — 子资源中不要添加所有者引用。 在CR创建的ConfigMap·Deployment·Service中ownerReferences加上的话会出现两种情况。第一,当父母被删除时,垃圾收集器会自动整理孩子。第二,控制器只管理“我做的”,调整范围变得明确。这里有一个重要的陷阱——**所有者引用不是名字uid连接。**删除同名父母后重新创建的话,uid会变更,指向旧uid的子孙会成为孤儿并立即被收走。
**纪律4 — status遵循conditions标准。**简单的phase: Running比起字符串,建议使用conditions数组。
| 领域 | 意义 |
|---|---|
type |
条件名称(Ready、Progressing、Degraded) |
status |
True / False / Unknown |
reason |
机器读取的简短理由代码 |
message |
人们阅读的说明 |
lastTransitionTime |
状态最后变更的时间 |
reason科message两者都设置的原因是核心。通知规则是reason分为,值班人员message读。只要有一件事,两件事中就有一件事就会不方便。
纪律5 — observedGeneration显示时差。metadata.generation银spec每次变动都会上升,status.observedGeneration是控制器最后处理的世代。如果两个不一样,就意味着“还没有反映最新的明细”。如果没有这双,用户就无法区分status是反映了新的spec还是旧spec的残留。
在现场相遇的样子
第一,只看status来判断的思维。 status是控制器缓存的观察结果,而不是真相的来源。真实状态在实际资源中。只看status来分支的控制器,当status过时时会做出错误的决定。
**第二,在status中无限堆叠数组的行为。**如果将事件或日志累积到status数组中,每次更新时,整个对象都会重新写入,informer缓存内存也会一起膨胀。应该使用像conditions一样大小固定的结构。
第三,定制栏和标签的组合。 CR作为正式对象的事实最实用的结果是标签选择器。spec.tier输入价格和metadata.labels.tier贴上是另一回事。前面的是控制器读取的意图,后面的是人和工具选择的索引。两者都需要。
下次实习要做的事情
crd-lab在命名空间中分别创建最小规格CR和全部规格CR,确认注入基本值,将子ConfigMap作为所有者引用绑定到父节点,在status子对象中直接写入观测值和Ready条件。然后用标签选择器和自定义列提取想要的东西,最后在CR的规格中创建从该规格派生出的“想要的状态”对象,准备进入下一个模块的调整循环。