线上K8s CRD 新增字段指南(无业务语义版)
线上K8s CRD 新增字段指南(无业务语义版)
1. 目标
本文总结一个可复用的工程流程:在 Kubernetes CRD 中新增字段,并确保代码生成、清单产物、集群校验、版本一致性全部可控。
2. 总体原则
types.go改动后,生成器流程必须重跑(即使部分产物最终无 diff)。- 生成器版本必须固定,避免不同开发机生成结果漂移。
- 声明式清单只保留期望态配置,避免提交服务端运行态字段。
- 验证要同时覆盖“代码侧”和“集群侧”。
3. 字段定义层(API Types)
3.1 选择字段位置
- 配置型字段放
spec。 - 观测/回显型字段放
status。 - 如果需要“实际生效值”可观测,可在
status增加同名回显字段。
3.2 定义 enum(示例)
1
2
3
4
5
6
7
8
9
10
11
type PolicyType string
const (
PolicyA PolicyType = "PolicyA"
PolicyB PolicyType = "PolicyB"
)
type ExampleSpec struct {
// +kubebuilder:validation:Enum=PolicyA;PolicyB
Policy PolicyType `json:"policy,omitempty"`
}
3.3 为什么有些字段不会改动 deepcopy 文件
- 值类型(如
string/int/bool及其别名)通常由*out = *in覆盖,不一定产生新代码。 - 引用类型(
slice/map/pointer)通常会生成单独拷贝逻辑(make+copy或递归拷贝)。
结论:必须重跑 deepcopy-gen,但不保证一定有 diff。
4. 代码生成层(必须执行)
建议统一跑完整链路:
deepcopy-genconversion-genclient-genlister-geninformer-gencontroller-gen(CRD YAML)
原因:
- 可以避免“以为不用重跑,实际遗漏”的风险。
- 即使
clientset/lister/informer无变更,也应由流程证明“已重跑且无变化”。
5. 版本锁定与可复现
5.1 固定工具版本
- 固定
code-generator版本。 - 固定
controller-gen版本。
5.2 本地工具目录
将二进制安装到仓库内目录(如 .tools/bin),不要依赖全局 $GOPATH/bin。
5.3 按版本校验后再安装
不要只判断“文件是否存在”,要校验模块版本:
1
go version -m <bin> | awk '$1=="mod"{print $2"@"$3; exit}'
若不匹配目标版本,再 go install ...@<version>。
5.4 老版本工具与新 Go 兼容性
某些老版本生成器在新 Go 工具链上可能异常,可单独指定:
1
GOTOOLCHAIN=go1.xx.yy go install <tool>@<version>
6. 仅更新目标 CRD 的安全策略
如果仓库含多个 CRD,但只希望更新其中一个:
controller-gen先输出到临时目录。- 只拷贝目标 CRD 文件回仓库。
- 严格检查其余 CRD 文件无 diff。
这能避免“全量重写所有 CRD”造成无关变更。
7. CRD 清单净化(建议)
生成后应去掉不需要提交的字段:
- 顶层
status:(CRD 对象运行态,由 apiserver 回填) metadata.creationTimestamp: null
保留:
spec.versions[*].subresources.status: {}(这是 CRD 能力配置,不是运行态)
8. 验证清单(Checklist)
8.1 代码与产物
git diff --name-only仅包含预期文件。- 目标字段出现在
types与目标 CRD schema。 - 非目标 CRD 不应被修改(如需求要求“只改一个 CRD”)。
8.2 编译/测试
go test ./...(至少保证编译通过)。- 如有 CI 生成一致性检查,确保通过。
8.3 集群侧校验
优先:
1
kubectl apply --dry-run=server -f <crd.yaml>
若集群不支持 --server-side(报 415 Unsupported Media Type),属于集群能力问题,可改用上面这条普通 server dry-run 校验。
9. 常见误区
误区:改了 types,clientset/lister/informer 一定有 diff。
实际:很多字段变更不会改变这些生成文件内容。误区:本地有工具二进制就算锁版本。
实际:可能是旧版本,必须做版本校验。误区:把 CRD 顶层
status一起提交更完整。
实际:这是运行态信息,通常不应进入声明式清单。
10. 最小执行模板(示意)
1
2
3
4
5
# 1) tools: 校验版本,不匹配则安装
# 2) codegen-all: 跑 deepcopy/conversion/client/lister/informer
# 3) crd-target: controller-gen 到临时目录,仅拷贝目标 CRD
# 4) post-process: 去掉顶层 status + creationTimestamp
# 5) verify: diff 范围与 go test
把以上流程固化为 Make 目标后,可以将“新增 CRD 字段”变成稳定、可审计、可复现的一步式操作。
This post is licensed under CC BY 4.0 by the author.