在这篇文章中,我将向您介绍如何使用kubebuilder轻松创建Kubernetes Operator。
在快速介绍 kubebuilder 后,我们将逐步创建一个 k8s Operator(以 kube-image-keeper Operator 为例,它是一个用于在 Kubernetes 集群中缓存镜像的开源工具)。最后,我们将讨论 kubebuilder 的优点和局限性。
让我们看一下使用 kubebuilder 创建 Kubernetes operator kube-image-keeper (kuik) 的具体示例。
现在,大家到你们的终端吧!我们将生成 kubebuilder 项目的基本脚手架(或样板)。为此,请在空文件夹中执行以下命令:
kubebuilder init \
--domain kuik.enix.io \
--repo github.com/enix/kube-image-keeper
其中“domain”对应我们要创建的资源的api组,“repo”对应项目所在的git仓库。
Kubebuilder创建了几个文件和文件夹,包括:
现在已经生成了基本项目,我们可以开始创建我们的控制器了。
我们将从CachedImageController开始,它的作用是监视CachedImage,并在删除CachedImage时将引用的图像缓存或从缓存中删除它们:
kubebuilder create api \
--kind CachedImage \
--version v1alpha1 \
--namespaced=false \
--resource=true \
--controller=true
为了生成负责监视Pods并创建CachedImages的控制器的基本结构,我们可以使用类似的命令。然而,我们指示Kubebuilder不要生成自定义资源定义(CRD),因为Pods已经是原生的Kubernetes资源。
kubebuilder create api \
--group core \
--kind Pod \
--version v1 \
--resource=false \
--controller=true
运行这两个命令后,我们会得到几个新文件。值得注意的是,在controllers文件夹中,我们可以找到两个文件cachedimage_controller.go和pod_controller.go,以及suite_test.go文件,其中包含了快速设置集成测试所需的内容。CachedImage类型在api/v1alpha1/cachedimage_types.go文件中定义。我们注意到main.go文件已经更新,用于启动我们的两个新控制器。最后,PROJECT文件现在包含有关资源和控制器设置的信息。
为了说明,pod_controller.go文件如下所示:
package controllers
import (
"context"
corev1 "k8s.io/api/core/v1"
"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"
)
// PodReconciler reconciles a Pod object
type PodReconciler struct {
client.Client
Scheme *runtime.Scheme
}
//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=core,resources=pods/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=core,resources=pods/finalizers,verbs=update
func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
// TODO(user): your logic here
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *PodReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.Pod{}).
Complete(r)
}
协调函数定义协调循环。这是实现控制器逻辑的地方。
一旦实现了控制器并定义了 CachedImage 类型,我们仍然需要生成 CRD 的 yaml 清单以将其安装在 Kubernetes 集群中。
注释
如果你打开cachedimage_types.go,你可以看到一个CachedImage的定义,它看起来像这样(完整的文件有点长,但这部分对你来说是最有趣的):
type CachedImageSpec struct {
Foo string `json:"foo,omitempty"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:resource:scope=Cluster
type CachedImage struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec CachedImageSpec `json:"spec,omitempty"`
Status CachedImageStatus `json:"status,omitempty"`
}
除了结构体之外,我们还可以看到各种注释。这些注解描述了如何生成相应的CRD。例如,+kubebuilder:resource:scope=Cluster 表示 CachedImage 没有命名空间。其他注释也可用,例如,您可以添加要在 kubectl get 期间显示的列,这要归功于注释 +kubebuilder:printcolumn:name=“Foo”,type=“string”,JSONPath=“.spec.foo”。在这种特定情况下,我们添加“Foo”列,显示 CachedImages 的 .spec.foo 值。
为了生成与我们的CRD相关的文件,我们将使用两个命令。
第一个命令make generate在调用kubebuilder create api命令时会自动执行,它会创建api/v1alpha1/zz_generated.deepcopy.go文件,该文件实现了操作符的某些关键函数,例如CachedImage.DeepCopy函数。
第二个命令是我们最感兴趣的命令:make manifests。这个命令会生成config/crd/bases/kuik.enix.io_cachedimages.yaml文件,其中包含了CRD的定义,我们随后可以将其安装到我们的Kubernetes集群中。
我们已经创建了两个控制器和我们的CRD,现在剩下的就是创建我们的变异webhook。
为了做到这一点,通常我们使用kubebuilder create webhook命令。然而,我们有一个小问题:kubebuilder不支持为“核心类型”创建webhook,而我们想要创建的webhook恰好是针对Pods的。因此,我们按照官方kubebuilder文档的说明,使用controller-runtime库自己创建此部分的样板代码。
如果您想为自定义资源创建webhook,就像创建控制器一样简单:
kubebuilder create webhook \
--kind CachedImage \
--version v1alpha1 \
--defaulting
您可以在 --conversion、–defaulting 和 --programmatic-validation 标志之间进行选择,以创建不同类型的 Webhook。必须至少提供这 3 个标志之一,对应于以下功能:
在配置控制器的各个组件之后,下一步显然是检查所有东西是否正常工作。为了做到这一点,我们实现了必要的测试,并重点关注suite_test.go文件中的集成测试。
为了执行测试,我们使用make test命令,该命令负责下载测试依赖项并执行它们。我们可以使用ENVTEST_K8S_VERSION环境变量选择要运行集成测试的Kubernetes API版本,例如ENVTEST_K8S_VERSION=1.25。但是要小心,只有控制平面的一部分会启动,即API服务器和etcd,但除我们创建的控制器之外的其他各种控制器不会被执行。因此,行为可能与预期略有不同。您可以在文档中找到更多细节。
为了简化开发过程,kubebuilder允许您使用’make run’命令在本地计算机上轻松运行操作符。当然,需要连接到您打算操作的Kubernetes集群。
然而,当您的操作符包含一个webhook时,需要采取一些预防措施。webhook需要一个证书以确保正常运行(在相应的MutatingWebhookConfiguration中指定的证书),并且发送到webhook的请求必须在集群外部发送。在这种情况下,我们将通过URL而不是Kubernetes服务在webhook配置(MutatingWebhookConfiguration.webhooks.clientConfig)中进行配置。文档建议在本地测试代码之前通过设置ENABLE_WEBHOOKS=false环境变量禁用webhook。
现在我们已经看到了使用kubebuilder创建Kubernetes操作符的用法,让我们来看看它的优势和局限性:
Kubebuilder的优势
Kubebuilder的局限性
Kubebuilder可以显著简化您的Kubernetes操作符的开发。它在启动新项目时似乎特别有价值。然而,根据操作符的不同,它也有一些限制,这使得它的使用变得复杂,并需要偏离工具的初始操作和文件组织。在这种情况下,您需要仔细评估是否继续使用Kubebuilder或转换为手动操作符更新。