写一个 CRD 之后,你的自定义资源在 API Server 里到底得到了哪些待遇?这篇把 schema 校验、剪枝、默认值和 status 子资源一项项真的跑了一遍,并直接去 etcd 里把存下来的 JSON 读出来,看默认值是什么时候被补上的。
[size=3] (0, 'widget.k3.example.com/w1 created')
读回 w1 的 spec:{"color":"red","size":3}
[size=0] 退出码 1;spec.size: Invalid value: 0: spec.size in body should be greater than or equal to 1
[缺少 size] 退出码 1;spec.size: Required value
[color=blue] 退出码 1;spec.color: Unsupported value: "blue": supported values: "red", "green"
[size="abc"] 退出码 1;spec.size: Invalid value: "string": spec.size in body must be of type integer: "string"
kubectl get widgets(附加打印列来自 additionalPrinterColumns):
NAME SIZE COLOR
w1 3 redCRD 的 openAPIV3Schema 在提交时就起作用:size=0 报 should be greater than or equal to 1,缺 size 报 Required value,color=blue 报 Unsupported value 并列出允许的值,类型错的报 must be of type integer。合法对象读回来多了 color: red,是 default 补的。kubectl get 的 SIZE、COLOR 两列来自 additionalPrinterColumns。
默认(服务端严格字段校验):退出码 1;Error from server (BadRequest): error when creating "STDIN": Widget in version "v1" cannot be handled as a Widget: strict decoding error: unknown field "spec.extra"
--validate=false:退出码 0;widget.k3.example.com/w2 created
读回 w2 的 spec:{"color":"red","size":2} ← extra 不见了
--validate=warn:退出码 0;widget.k3.example.com/w2 configured Warning: unknown field "spec.extra"schema 里没声明的字段不会被保留。kubectl 默认开着服务端严格字段校验,直接报 strict decoding error: unknown field "spec.extra";用 --validate=false 绕过去,请求被接受,但读回来 extra 已经被剪掉(pruning);--validate=warn 则是剪掉并给出 Warning。想保留未知字段要在 schema 里写 x-kubernetes-preserve-unknown-fields: true。
etcd key /registry/k3.example.com/widgets/k3/w1
存进去的 JSON:apiVersion=k3.example.com/v1 kind=Widget spec={"color": "red", "size": 3} metadata 字段:['annotations', 'creationTimestamp', 'generation', 'managedFields', 'name', 'namespace', 'uid']
给 CRD 新增一个带默认值的字段 spec.shape(default: circle)之后:
读 w1 的 spec:{"color":"red","shape":"circle","size":3}
etcd 里 w1 的 spec:{"color": "red", "size": 3} ← 没有 shape,默认值只在读的时候补CR 以 JSON 存在 /registry/<group>/<resource>/<ns>/<name>。w1 存进去的 spec 是 {"color": "red", "size": 3}:写入时补的默认值已经固化。之后给 CRD 加一个带默认值的字段 shape,读 w1 马上看到 "shape":"circle",但 etcd 里的 spec 一个字没变——CRD 事后新增的默认值是在读出来的时候补上的,不会改写旧对象。
初始:generation=1 status=(空)
patch 主资源写 status.ready=true:widget.k3.example.com/w1 patched;读回 status=(空)
patch --subresource=status 写同样的内容:widget.k3.example.com/w1 patched;读回 status={"ready":true};generation=1
通过 status 子资源改 spec.size=9:widget.k3.example.com/w1 patched (no change);读回 spec.size=3
通过主资源改 spec.size=5:widget.k3.example.com/w1 patched;读回 spec.size=5;generation=2开了 subresources.status 之后,主资源和 /status 各管各的:往主资源 patch status 被忽略,往 /status patch spec 也被忽略(no change)。metadata.generation 只在 spec 变化时加 1,所以控制器可以用 generation 和 status.observedGeneration 判断自己处理的是不是最新的 spec。