你提到了主要内容?

但首先,记得我们说过我们会再次回到 main.go 吗?让我们来看看发生了什么变化,以及我们需要添加什么。

project/cmd/main.go
Apache 许可证

版权所有 2024 年 Kubernetes 作者。

根据 Apache 许可证 2.0 版(“许可证”)获得许可; 除非符合许可证的规定,否则您不得使用此文件。 您可以在以下网址获取许可证的副本:

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

除非适用法律要求或书面同意,根据许可证分发的软件是基于“按原样“的基础分发的, 没有任何明示或暗示的担保或条件。 请查看许可证以了解特定语言管理权限和限制。

Imports
package main

import (
	"crypto/tls"
	"flag"
	"os"

	// 导入所有 Kubernetes 客户端认证插件(例如 Azure、GCP、OIDC 等)
	// 以确保 exec-entrypoint 和 run 可以利用它们。
	_ "k8s.io/client-go/plugin/pkg/client/auth"

	"k8s.io/apimachinery/pkg/runtime"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/healthz"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"
	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
	"sigs.k8s.io/controller-runtime/pkg/webhook"

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

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

如果我们将使用任何其他 CRD,我们将不得不以相同的方式添加它们的 scheme。 诸如 Job 之类的内置类型通过 clientgoscheme 添加了它们的 scheme。

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

func init() {
	utilruntime.Must(clientgoscheme.AddToScheme(scheme))

	utilruntime.Must(batchv1.AddToScheme(scheme))
	//+kubebuilder:scaffold:scheme
}

另一个发生变化的地方是,kubebuilder 已添加了一个块,调用我们的 CronJob 控制器的 SetupWithManager 方法。

func main() {
old stuff
	var metricsAddr string
	var enableLeaderElection bool
	var probeAddr string
	var secureMetrics bool
	var enableHTTP2 bool
	flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
	flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "leader-elect", false,
		"Enable leader election for controller manager. "+
			"Enabling this will ensure there is only one active controller manager.")
	flag.BoolVar(&secureMetrics, "metrics-secure", false,
		"If set the metrics endpoint is served securely")
	flag.BoolVar(&enableHTTP2, "enable-http2", false,
		"If set, HTTP/2 will be enabled for the metrics and webhook servers")
	opts := zap.Options{
		Development: true,
	}
	opts.BindFlags(flag.CommandLine)
	flag.Parse()

	ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

	// 如果 enable-http2 标志为 false(默认值),则应禁用 http/2
	// 由于其漏洞。更具体地说,禁用 http/2 将防止受到 HTTP/2 流取消和
	// 快速重置 CVE 的影响。更多信息请参见:
	// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
	// - https://github.com/advisories/GHSA-4374-p667-p6c8
	disableHTTP2 := func(c *tls.Config) {
		setupLog.Info("disabling http/2")
		c.NextProtos = []string{"http/1.1"}
	}

	tlsOpts := []func(*tls.Config){}
	if !enableHTTP2 {
		tlsOpts = append(tlsOpts, disableHTTP2)
	}

	webhookServer := webhook.NewServer(webhook.Options{
		TLSOpts: tlsOpts,
	})

	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme: scheme,
		Metrics: metricsserver.Options{
			BindAddress:   metricsAddr,
			SecureServing: secureMetrics,
			TLSOpts:       tlsOpts,
		},
		WebhookServer:          webhookServer,
		HealthProbeBindAddress: probeAddr,
		LeaderElection:         enableLeaderElection,
		LeaderElectionID:       "80807133.tutorial.kubebuilder.io",
		// LeaderElectionReleaseOnCancel 定义了在 Manager 结束时领导者是否应主动下台
		//。这需要二进制文件在 Manager 停止后立即结束,否则,此设置是不安全的。设置这将显著
		// 加快自愿领导者过渡的速度,因为新领导者无需等待 LeaseDuration 时间。
		//
		// 在默认提供的脚手架中,程序在 Manager 停止后立即结束,因此可以启用此选项。
		// 但是,如果您正在执行或打算在 Manager 停止后执行任何操作,比如执行清理操作,
		// 那么它的使用可能是不安全的。
		// LeaderElectionReleaseOnCancel: true,
	})
	if err != nil {
		setupLog.Error(err, "unable to start manager")
		os.Exit(1)
	}
	if err = (&controller.CronJobReconciler{
		Client: mgr.GetClient(),
		Scheme: mgr.GetScheme(),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "CronJob")
		os.Exit(1)
	}
old stuff

我们还将为我们的类型设置 webhooks,接下来我们将讨论它们。 我们只需要将它们添加到 manager 中。由于我们可能希望单独运行 webhooks, 或者在本地测试控制器时不运行它们,我们将它们放在一个环境变量后面。

我们只需确保在本地运行时设置 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", "CronJob")
			os.Exit(1)
		}
	}
	//+kubebuilder:scaffold:builder

	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
		setupLog.Error(err, "unable to set up health check")
		os.Exit(1)
	}
	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
		setupLog.Error(err, "unable to set up ready check")
		os.Exit(1)
	}

	setupLog.Info("starting manager")
	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
}

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