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

你还记得关于 main 函数的一些要点吗?

但首先,还记得我们之前说过的 再次回顾 main.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


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 main

import (

	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	ctrl "sigs.k8s.io/controller-runtime"

	batchv1 "tutorial.kubebuilder.io/project/api/v1"
	// +kubebuilder:scaffold:imports

要注意的第一个区别是 kubebuilder 已经添加了一组新的 API 包(batchv1)到 scheme。这意味着可以在我们的控制器中使用这些对象。

如果我们要使用任何其他的 CRD,我们必须用相同的方法添加它们的 scheme。内置的类型例如 Job 就添加了它自己的 scheme clientgoscheme

var (
	scheme   = runtime.NewScheme()
	setupLog = ctrl.Log.WithName("setup")

func init() {

	// +kubebuilder:scaffold:scheme

另一个变化是 kubebuilder 已经添加了一个阻塞调用我们的 CornJob 控制器的 SetupWithManager 方法。

func main() {
old stuff
	var metricsAddr string
	var enableLeaderElection bool
	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
		"Enable leader election for controller manager. "+
			"Enabling this will ensure there is only one active controller manager.")


	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:             scheme,
		MetricsBindAddress: metricsAddr,
		Port:               9443,
		LeaderElection:     enableLeaderElection,
		LeaderElectionID:   "80807133.tutorial.kubebuilder.io",
	if err != nil {
		setupLog.Error(err, "unable to start manager")
	if err = (&controllers.CronJobReconciler{
		Client: mgr.GetClient(),
		Log:    ctrl.Log.WithName("controllers").WithName("CronJob"),
		Scheme: mgr.GetScheme(),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "CronJob")
	if err = (&batchv1.CronJob{}).SetupWebhookWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create webhook", "webhook", "CronJob")
我们也会为我们的类型设置 webhook,接下来我们会谈到它。我们只需要将他们添加到 manager。因为我们想分开运行 webhook,而不是在本地测试我们的控制器时运行它们,我们会将它们配置到环境变量中。

当我们本地运行的时候只需确保 ENABLE_WEBHOOKS=false

	if os.Getenv("ENABLE_WEBHOOKS") != "false" {
		if err = (&batchv1.CronJob{}).SetupWebhookWithManager(mgr); err != nil {
			setupLog.Error(err, "unable to create webhook", "webhook", "Captain")
	// +kubebuilder:scaffold:builder
old stuff
	setupLog.Info("starting manager")
	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")

现在 我们可以实现我们的控制器了。