kubebuilder 中文文档由云原生社区主导翻译。任何问题可以在这儿提issue。issue模版可以参考这个

修改

Kubernetes API 中一个相当常见的改变是获取一些非结构化的或者存储在一些特殊的字符串格式的数据, 并将其修改为结构化的数据。我们的 schedule 字段非常适合这个案例 -- 现在,在 v1 中,我们的 schedules 是这样的

schedule: "*/1 * * * *"

这是一个非常典型的特殊字符串格式的例子(除非你是一个 Unix 系统管理员,否则非常难以理解它)。

让我们来使它更结构化一点。根据我们 CronJob 代码,我们支持”standard” Cron 格式。

在 Kubernetes 里,所有版本都必须通过彼此进行安全的往返。这意味着如果我们从版本 1 转换到版本 2,然后回退到版本 1,我们一定会失去一些信息。因此,我们对 API 所做的任何更改都必须与 v1 中所支持的内容兼容还需要确保我们添加到 v2 中的任何内容在 v1 中都得到支持。某些情况下,这意味着我们需要向 V1 中添加新的字段,但是在我们这个例子中,我们不会这么做,因为我们没有添加新的功能。

记住这些,让我们将上面的示例转换为稍微更结构化一点:

schedule:
  minute: */1

现在,至少我们每个字段都有了标签,但是我们仍然可以为每个字段轻松地支持所有不同的语法。

对这个改变我们将需要一个新的 API 版本。我们称它为 v2:

kubebuilder create api --group batch --version v2 --kind CronJob

现在,让我们复制已经存在的类型,并做一些改变:

project/api/v2/cronjob_types.go
Apache License

Copyright 2020 The Kubernetes authors.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

因为我们现在在v2 包中,controller-gen 将自动假设这是对于 v2 版本的。 我们可以用+versionNamemarker去重写它。

package v2
Imports
import (
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// 编辑这个文件!这是你拥有的脚手架!
// 注意: json 标签是必需的。为了字段能够被序列化任何你添加的新的字段一定有 json 标签。

除了将 schedule 字段更改为一个新类型外,我们将基本上保持 spec 不变。

// CronJobSpec 定义了 CronJob 期待的状态
type CronJobSpec struct {
	// Cron 格式的 schedule,详情请看https://en.wikipedia.org/wiki/Cron。
	Schedule CronSchedule `json:"schedule"`
The rest of Spec
	// +kubebuilder:validation:Minimum=0

	// 对于开始 job 以秒为单位的可选的并如果由于任何原因错失了调度的时间截止日期。未执行的
	// job 将被统计为失败的 job 。
	// +optional
	StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds,omitempty"`

	// 指定如何处理job的并发执行。
	// 有效的值是:
	// - "Allow" (默认): 允许 CronJobs 并发执行;
	// - "Forbid":禁止并发执行,如果之前运行的还没有完成,跳过下一次执行;
	// - "Replace": 取消当前正在运行的 job 并用新的 job 替换它
	// +optional
	ConcurrencyPolicy ConcurrencyPolicy `json:"concurrencyPolicy,omitempty"`

	// 此标志告诉控制器暂停后续执行,它不会应用到已经开始执行的 job 。默认值是 false。
	// +optional
	Suspend *bool `json:"suspend,omitempty"`

	// 指定当执行一个 CronJob 时将会被创建的 job 。
	JobTemplate batchv1beta1.JobTemplateSpec `json:"jobTemplate"`

	// +kubebuilder:validation:Minimum=0

	// 要保留的成功完成的 jobs 的数量。
	// 这是一个用来区分明确 0 值和未指定的指针。
	// +optional
	SuccessfulJobsHistoryLimit *int32 `json:"successfulJobsHistoryLimit,omitempty"`

	// +kubebuilder:validation:Minimum=0

	// 要保留的失败的 jobs 的数量。
	// 这是一个用来区分明确 0 值和未指定的指针。
	// +optional
	FailedJobsHistoryLimit *int32 `json:"failedJobsHistoryLimit,omitempty"`
}

接下来,我们定义一个类型存储我们的 schedule 。 基于我们上面提议的 YAML 格式,每个对应的 Cron “field” 都有一个字段。

// 描述一个Cron schedule。
type CronSchedule struct {
	// 指定 job 执行的分钟数。
	// +optional
	Minute *CronField `json:"minute,omitempty"`
	// 指定 job 执行的小时数。
	// +optional
	Hour *CronField `json:"hour,omitempty"`
	// 指定 job 执行的月的天数。
	// +optional
	DayOfMonth *CronField `json:"dayOfMonth,omitempty"`
	// 指定 job 执行的月数。
	// +optional
	Month *CronField `json:"month,omitempty"`
	// 指定 job 执行的一周的天数。
	// +optional
	DayOfWeek *CronField `json:"dayOfWeek,omitempty"`
}

最后,我们定义一个封装器类型来表示一个字段。 我们可以为这个字段附加一些额外的验证,但是现在我们只仅仅用它做文档的目的。

// 表示一个 Cron 字段说明符。
type CronField string
Other Types

所有其他类型将保持与以前相同。

// ConcurrencyPolicy 描述 job 将会被怎样处理。仅仅下面并发策略中的一种可以被指定。
// 如果没有指定下面策略的任何一种,那么默认的一个是 AllowConcurrent 。
// +kubebuilder:validation:Enum=Allow;Forbid;Replace
type ConcurrencyPolicy string

const (
	// AllowConcurrent 允许 CronJobs 并发执行.
	AllowConcurrent ConcurrencyPolicy = "Allow"

	// ForbidConcurrent 禁止并发执行, 如果之前运行的还没有完成,跳过下一次执行
	ForbidConcurrent ConcurrencyPolicy = "Forbid"

	// ReplaceConcurrent 取消当前正在运行的 job 并用新的 job 替换它。
	ReplaceConcurrent ConcurrencyPolicy = "Replace"
)

// CronJobStatus 定义了 CronJob 观察的的状态
type CronJobStatus struct {
	// 插入额外的 STATUS 字段 - 定义集群观察的状态
	// 重要:修改了这个文件之后运行"make"去重新生成代码

	// 一个存储当前正在运行 job 的指针列表。
	// +optional
	Active []corev1.ObjectReference `json:"active,omitempty"`

	// 当 job 最后一次成功被调度的信息。
	// +optional
	LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// CronJob 是 cronjobs API 的 Schema
type CronJob struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   CronJobSpec   `json:"spec,omitempty"`
	Status CronJobStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// CronJobList 包含了一个 CronJob 的列表
type CronJobList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []CronJob `json:"items"`
}

func init() {
	SchemeBuilder.Register(&CronJob{}, &CronJobList{})
}

存储版本

project/api/v1/cronjob_types.go
Apache License

Copyright 2020 The Kubernetes authors.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

package v1
Imports
import (
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// 编辑这个文件!这是你拥有的脚手架!
// 注意: json 标签是必需的。为了字段能够被序列化任何你添加的新的字段一定有 json 标签。
old stuff
// CronJobSpec 定义了 CronJob 期待的状态
type CronJobSpec struct {
	// +kubebuilder:validation:MinLength=0

	// Cron 格式的 schedule,详情请看https://en.wikipedia.org/wiki/Cron。
	Schedule string `json:"schedule"`

	// +kubebuilder:validation:Minimum=0

	// 对于开始 job 以秒为单位的可选的并如果由于任何原因错失了调度的时间截止日期。未执行的
	// job 将被统计为失败的 job 。
	// +optional
	StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds,omitempty"`

	// 指定如何处理job的并发执行。
	// 有效的值是:
	// - "Allow" (默认): 允许 CronJobs 并发执行;
	// - "Forbid":禁止并发执行,如果之前运行的还没有完成,跳过下一次执行;
	// - "Replace": 取消当前正在运行的 job 并用新的 job 替换它
	// +optional
	ConcurrencyPolicy ConcurrencyPolicy `json:"concurrencyPolicy,omitempty"`

	// 此标志告诉控制器暂停后续执行,它不会应用到已经开始执行的 job 。默认值是 false。
	// +optional
	Suspend *bool `json:"suspend,omitempty"`

	// 指定当执行一个 CronJob 时将会被创建的 job 。
	JobTemplate batchv1beta1.JobTemplateSpec `json:"jobTemplate"`

	// +kubebuilder:validation:Minimum=0

	// 要保留的成功完成的 jobs 的数量。
	// 这是一个用来区分明确 0 值和未指定的指针。
	// +optional
	SuccessfulJobsHistoryLimit *int32 `json:"successfulJobsHistoryLimit,omitempty"`

	// +kubebuilder:validation:Minimum=0

	// 要保留的失败的 jobs 的数量。
	// 这是一个用来区分明确 0 值和未指定的指针。
	// +optional
	FailedJobsHistoryLimit *int32 `json:"failedJobsHistoryLimit,omitempty"`
}

// ConcurrencyPolicy 描述 job 将会被怎样处理。仅仅下面并发策略中的一种可以被指定。
// 如果没有指定下面策略的任何一种,那么默认的一个是 AllowConcurrent 。
// +kubebuilder:validation:Enum=Allow;Forbid;Replace
type ConcurrencyPolicy string

const (
	// AllowConcurrent 允许 CronJobs 并发执行.
	AllowConcurrent ConcurrencyPolicy = "Allow"

	// ForbidConcurrent 禁止并发执行, 如果之前运行的还没有完成,跳过下一次执行
	// hasn't finished yet.
	ForbidConcurrent ConcurrencyPolicy = "Forbid"

	// ReplaceConcurrent 取消当前正在运行的 job 并用新的 job 替换它。
	ReplaceConcurrent ConcurrencyPolicy = "Replace"
)

// CronJobStatus 定义了 CronJob 观察的的状态
type CronJobStatus struct {
	// 插入额外的 STATUS 字段 - 定义集群观察的状态
	// 重要:修改了这个文件之后运行"make"去重新生成代码

	// 一个存储当前正在运行 job 的指针列表。
	// +optional
	Active []corev1.ObjectReference `json:"active,omitempty"`

	// 当 job 最后一次成功被调度的信息。
	// +optional
	LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"`
}

因为我们将有多个版本,我们将需要标记一个存储版本。 这是一个 Kubernetes API 服务端使用存储我们数据的版本。 我们将选择v1版本作为我们项目的版本。

我们将用 +kubebuilder:storageversion 去做这件事。

注意如果在存储版本改变之前它们已经被写入那么在仓库中可能存在多个版本 -- 改变存储版本仅仅影响 在改变之后对象的创建/更新。

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:storageversion

// CronJob 是 cronjobs API 的 Schema
type CronJob struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   CronJobSpec   `json:"spec,omitempty"`
	Status CronJobStatus `json:"status,omitempty"`
}
old stuff
// +kubebuilder:object:root=true

// CronJobList 包含了一个 CronJob 的列表
type CronJobList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []CronJob `json:"items"`
}

func init() {
	SchemeBuilder.Register(&CronJob{}, &CronJobList{})
}

现在我们已经准备好了类型,接下来需要设置转换。