我以前很容易把“记录了安装方式”和“记录了组件本身”混成一件事。后来在共享集群里处理越来越多 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 也放进仓库,才真正有管理价值。否则它更像是一份沉重但不常读的快照。

我现在更认可的沉淀顺序

如果让我给自己定一条更稳定的规则,我会这样排:

  1. 先记录安装入口;
  2. 再记录 values;
  3. 再记录生命周期策略;
  4. 最后才决定要不要把 CRD 原文也纳入仓库。

这个顺序的好处是,它逼着我先回答“以后如何重复做对同一件事”,而不是先堆一份看起来完整、实际上不一定常用的 YAML。

对我的提醒

这次让我更确定一个判断:配置仓库最宝贵的不是存了多少上游原文,而是有没有把自己的运维边界清楚地写出来。

CRD 也一样。对共享集群来说,最重要的从来不是“字段有多少”,而是“谁安装、谁升级、谁保留、谁负责漂移”。一旦把这些边界写清楚,CRD 才真正从一个 API 定义,变成一套可维护的集群资产。


相关页面:clickhouse-operator-installation-on-shared-clusters · kubernetes-api-groups-and-schema-validation