控制器的内容是什么?

控制器是 Kubernetes 和任何操作者的核心。

控制器的工作是确保对于任何给定的对象,世界的实际状态(集群状态,以及可能是 Kubelet 的运行容器或云提供商的负载均衡器等外部状态)与对象中的期望状态相匹配。每个控制器专注于一个 Kind,但可能会与其他 Kinds 交互。

我们称这个过程为调和

在 controller-runtime 中,实现特定 Kind 的调和逻辑称为Reconciler。调和器接受一个对象的名称,并返回我们是否需要再次尝试(例如在出现错误或周期性控制器(如 HorizontalPodAutoscaler)的情况下)。

emptycontroller.go
Apache License

版权所有 2022。

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

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

除非适用法律要求或书面同意,根据许可分发的软件是基于“按原样“的基础分发的, 不附带任何明示或暗示的担保或条件。 请参阅许可以获取特定语言下的权限和限制。

首先,我们从一些标准的导入开始。 与之前一样,我们需要核心的 controller-runtime 库,以及 client 包和我们的 API 类型包。

package controllers

import (
	"context"

	"k8s.io/apimachinery/pkg/runtime"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"

	batchv1 "tutorial.kubebuilder.io/project/api/v1"
)

接下来,kubebuilder 为我们生成了一个基本的 reconciler 结构。 几乎每个 reconciler 都需要记录日志,并且需要能够获取对象,因此这些都是开箱即用的。

// CronJobReconciler reconciles a CronJob object
type CronJobReconciler struct {
	client.Client
	Scheme *runtime.Scheme
}

大多数控制器最终都会在集群上运行,因此它们需要 RBAC 权限,我们使用 controller-tools 的 RBAC markers 来指定这些权限。这些是运行所需的最低权限。 随着我们添加更多功能,我们将需要重新审视这些权限。

// +kubebuilder:rbac:groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=batch.tutorial.kubebuilder.io,resources=cronjobs/status,verbs=get;update;patch

ClusterRole manifest 位于 config/rbac/role.yaml,通过以下命令使用 controller-gen 从上述标记生成:

// make manifests

注意:如果收到错误,请运行错误中指定的命令,然后重新运行 make manifests

Reconcile 实际上执行单个命名对象的对账。 我们的 Request 只有一个名称,但我们可以使用 client 从缓存中获取该对象。

我们返回一个空结果和没有错误,这表示 controller-runtime 我们已成功对账了此对象,并且在有变更之前不需要再次尝试。

大多数控制器需要一个记录句柄和一个上下文,因此我们在这里设置它们。

context 用于允许取消请求,以及可能的跟踪等功能。它是所有 client 方法的第一个参数。Background 上下文只是一个基本上没有任何额外数据或时间限制的上下文。

记录句柄让我们记录日志。controller-runtime 通过一个名为 logr 的库使用结构化日志。很快我们会看到,日志记录通过将键值对附加到静态消息上来实现。我们可以在我们的 reconciler 的顶部预先分配一些键值对,以便将它们附加到此 reconciler 中的所有日志行。

func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	_ = log.FromContext(ctx)

	// your logic here

	return ctrl.Result{}, nil
}

最后,我们将此 reconciler 添加到 manager 中,以便在启动 manager 时启动它。

目前,我们只指出此 reconciler 作用于 CronJob。稍后,我们将使用这个来标记我们关心相关的对象。

func (r *CronJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&batchv1.CronJob{}).
		Complete(r)
}

现在我们已经看到了调和器的基本结构,让我们填写 CronJob 的逻辑。