我以前很容易把“记录了安装方式”和“记录了组件本身”混成一件事。后来在共享集群里处理越来越多 Operator 和基础组件,我才慢慢意识到,这两者最好分开。否则仓库里看起来像是“什么都记下来了”,实际上却没有真正记住以后最需要复现的那部分判断。
这次围绕 ClickHouse Operator 和 clickhouse.com 这套 CRD,我最后得到的结论很明确:CRD 要记录,但默认不该把整份上游 CRD YAML 当成主要沉淀对象。
我真正想保留的是什么
如果我回头看一次共享集群里的 Operator 安装,真正有复用价值的通常不是“上游 CRD 长什么样”,而是下面这些东西:
- chart 是从哪里来的;
- 版本 pin 在哪一版;
- values 里开了什么、关了什么;
- CRD 是不是由 Helm 安装;
- 卸载 release 时,CRD 是不是保留;
- Operator 到底 watch 哪些 namespace。
这些信息决定的是以后怎么重装、怎么升级、怎么审计、怎么划边界。换句话说,它们描述的是你的集群决策,不是上游发行物的字面内容。
为什么我不默认 vendoring 整份 CRD
原因其实很现实。
第一,CRD 原文通常很大,而且大部分内容并不是我会手工维护的。真把它整份放进仓库后,往往只会出现两种结局:
- 它长期不动,慢慢和实际安装版本漂移;
- 它跟着上游反复更新,但本地没人愿意认真 review 那种巨大的机器生成 diff。
第二,这种做法容易制造一种错觉,好像“仓库里已经存了 CRD,所以以后就更可控”。可很多时候,真正不清楚的恰恰不是 CRD 字段,而是:
- 这套 CRD 是不是应该跟 release 一起升级;
- 共享集群里谁有权改它;
- 卸载时到底删不删;
- 它和业务资源发布是不是要解耦。
这些问题不写清楚,光多一份 YAML,控制力并不会真的变强。
那为什么 cert-manager 看起来像另一回事
我觉得这里最容易误判。
很多团队会给 cert-manager 单独开一个目录,里面放:
values.yaml- issuer
- webhook
- DNS provider 配置
看上去像是在“完整记录 cert-manager”,但我更愿意把它理解成:记录的是“这套组件如何在这个环境里被使用”。它真正沉淀下来的,是环境配置和使用方式,而不是把上游 CRD 原文抄一份回来。
ClickHouse Operator 其实也该沿用同一种思路。真正该保留的是:
- Helm values;
- 安装文档;
- watch 范围;
- CRD 生命周期策略;
- 与之配套的目标集群 manifest。
什么时候我会愿意把整份 CRD 也落库
也不是永远不需要。
如果出现下面这些约束,我会改变判断:
- 需要离线安装;
- 需要非常严格的变更审计;
- 团队要求所有集群级定义都显式 vendoring;
- 不想让 Helm 在安装时再动态决定 CRD 内容。
只有在这种前提下,把整份 CRD 也放进仓库,才真正有管理价值。否则它更像是一份沉重但不常读的快照。
我现在更认可的沉淀顺序
如果让我给自己定一条更稳定的规则,我会这样排:
- 先记录安装入口;
- 再记录 values;
- 再记录生命周期策略;
- 最后才决定要不要把 CRD 原文也纳入仓库。
这个顺序的好处是,它逼着我先回答“以后如何重复做对同一件事”,而不是先堆一份看起来完整、实际上不一定常用的 YAML。
对我的提醒
这次让我更确定一个判断:配置仓库最宝贵的不是存了多少上游原文,而是有没有把自己的运维边界清楚地写出来。
CRD 也一样。对共享集群来说,最重要的从来不是“字段有多少”,而是“谁安装、谁升级、谁保留、谁负责漂移”。一旦把这些边界写清楚,CRD 才真正从一个 API 定义,变成一套可维护的集群资产。
相关页面:clickhouse-operator-installation-on-shared-clusters · kubernetes-api-groups-and-schema-validation