生成 CRD(Generating CRDs)

Kubebuilder 使用名为 controller-gen 的工具来生成实用代码与 Kubernetes 对象 YAML(例如 CRD)。

它依赖源码中的特殊“标记注释”(以 // + 开头)来为字段、类型与包提供额外元信息。针对 CRD,相关标记通常写在你的 _types.go 文件中。更多标记说明请参考标记参考文档

Kubebuilder 提供了一个 make 目标来运行 controller-gen 以生成 CRD:make manifests

执行 make manifests 后,你会在 config/crd/bases 目录下看到生成的 CRD。make manifests 还会生成其他若干产物——详见标记参考文档

校验(Validation)

CRD 在其 validation 段落中通过 OpenAPI v3 schema 支持声明式校验

通常,校验相关标记可以加在字段或类型上。若校验逻辑较复杂、需要复用,或需要校验切片元素,建议定义一个新的类型以承载你的校验描述。

例如:

type ToySpec struct {
	// +kubebuilder:validation:MaxLength=15
	// +kubebuilder:validation:MinLength=1
	Name string `json:"name,omitempty"`

	// +kubebuilder:validation:MaxItems=500
	// +kubebuilder:validation:MinItems=1
	// +kubebuilder:validation:UniqueItems=true
	Knights []string `json:"knights,omitempty"`

	Alias   Alias   `json:"alias,omitempty"`
	Rank    Rank    `json:"rank"`
}

// +kubebuilder:validation:Enum=Lion;Wolf;Dragon
type Alias string

// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=3
// +kubebuilder:validation:ExclusiveMaximum=false
type Rank int32

自定义输出列(Additional Printer Columns)

自 Kubernetes 1.11 起,kubectl get 可以向服务端询问应显示哪些列。对 CRD 而言,这使其能像内建资源一样,在 kubectl get 中展示更贴合类型的信息。

展示哪些信息由 CRD 的 additionalPrinterColumns 字段控制,而该字段又由你在 Go 类型上标注的 +kubebuilder:printcolumn 标记决定。

例如,下面示例为之前的校验示例添加几列,显示 aliasrankknights 的信息:

// +kubebuilder:printcolumn:name="Alias",type=string,JSONPath=`.spec.alias`
// +kubebuilder:printcolumn:name="Rank",type=integer,JSONPath=`.spec.rank`
// +kubebuilder:printcolumn:name="Bravely Run Away",type=boolean,JSONPath=`.spec.knights[?(@ == "Sir Robin")]`,description="when danger rears its ugly head, he bravely turned his tail and fled",priority=10
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
type Toy struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   ToySpec   `json:"spec,omitempty"`
	Status ToyStatus `json:"status,omitempty"`
}

子资源(Subresources)

自 Kubernetes 1.13 起,CRD 可以选择实现 /status/scale 子资源

一般建议:凡是具有 status 字段的资源,都应启用 /status 子资源。

上述两个子资源均有对应的标记

Status

使用 +kubebuilder:subresource:status 启用 status 子资源。启用后,对主资源的更新不会直接修改其 status;同样,对 status 子资源的更新也只能修改 status 字段。

例如:

// +kubebuilder:subresource:status
type Toy struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   ToySpec   `json:"spec,omitempty"`
	Status ToyStatus `json:"status,omitempty"`
}

Scale

使用 +kubebuilder:subresource:scale 启用 scale 子资源。启用后,用户可以对你的资源使用 kubectl scale。若 selectorpath 指向标签选择器的字符串形式,HPA 也能自动伸缩你的资源。

例如:

type CustomSetSpec struct {
	Replicas *int32 `json:"replicas"`
}

type CustomSetStatus struct {
	Replicas int32 `json:"replicas"`
    Selector string `json:"selector"` // this must be the string form of the selector
}


// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
type CustomSet struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   CustomSetSpec   `json:"spec,omitempty"`
	Status CustomSetStatus `json:"status,omitempty"`
}

多版本(Multiple Versions)

自 Kubernetes 1.13 起,你可以在同一个 CRD 中定义某个 Kind 的多个版本,并通过 Webhook 在版本间进行转换。

更多细节见多版本教程

出于与旧版 Kubernetes 的兼容性考虑,Kubebuilder 默认不会为不同版本生成不同的校验规则。

如需启用,请修改 Makefile 中的选项:若使用 v1beta CRD,将 CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false 改为 CRD_OPTIONS ?= crd:preserveUnknownFields=false;若使用 v1(推荐),则为 CRD_OPTIONS ?= crd

随后,可使用 +kubebuilder:storageversion 标记 指定由 API Server 用于持久化数据的 GVK

实现细节(Under the hood)

Kubebuilder 通过脚手架提供了运行 controller-gen 的 make 规则;若本地尚无该可执行文件,会使用 Go Modules 的 go install 自动安装。

你也可以直接运行 controller-gen 来观察其行为。

controller-gen 的每个“生成器”都通过命令行选项进行控制(语法与标记一致)。同时它也支持不同的输出“规则”,用于控制产物的输出位置与形式。如下所示为 manifests 规则(为示例简化为仅生成 CRD):

# Generate manifests for CRDs
manifests: controller-gen
	$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

它通过 output:crd:artifacts 输出规则将与 CRD 相关的配置类(非代码)产物输出至 config/crd/bases,而非 config/crd

想要查看 controller-gen 的所有生成器与选项,运行:

controller-gen -h

or, for more details:

$ controller-gen -hhh