ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

使用 Kubebuilder 从零构建 CronJob 控制器:API、Reconciler、Webhook 与测试完整实战

使用 Kubebuilder 从零构建 CronJob 控制器:API、Reconciler、Webhook 与测试完整实战 开发者工具代码生成CLI云原生后端【免费下载链接】kubebuilderKubebuilder - SDK for building Kubernetes APIs using CRDs项目地址https://gitcode.com/gh_mirrors/ku/kubebuilder点击查看免费下载本文是一份以 Kubebuilder 官方教程为核心的端到端实战指南模拟「用 Kubebuilder 重写 Kubernetes 内置 CronJob 控制器」这一真实场景逐步完成项目脚手架搭建、GVK/API 设计、Reconciler 实现、本地运行与集群部署、默认/校验 Webhook 接入以及 envtest 集成测试。读完本文你将掌握 Kubebuilder本仓库所开发的 SDK从kubebuilder init到make deploy的完整开发闭环并能独立为自定义 Kind 编写类型定义、控制器与测试。教程对应的可运行示例工程与中间产物都位于仓库 docs/book/src/cronjob-tutorial/testdata 目录完整工程在 testdata/project其余中间状态文件空 API、空控制器、空 main.go直接散落在 testdata 目录下全文代码均可对照阅读。教程背景为什么选择 CronJob很多教程要么从过于刻意的小玩具应用讲起要么讲完基础知识就戛然而止。本教程则希望带你走完 Kubebuilder 几乎全部的能力梯度从最简单的脚手架开始一步步构建出一个功能相当完整的控制器。假想场景你已经厌倦了 Kubernetes 中非 Kubebuilder 实现版本的 CronJob 控制器带来的维护负担希望用 Kubebuilder 把它重写一遍。CronJob 控制器的工作是「按固定时间间隔在集群上运行一次性任务」它构建在 Job 控制器之上Job 负责把一次性任务运行到完成。我们不去重写 Job 控制器而是把它当作「外部类型」来交互——这恰好示范了如何在自己的控制器中编排 Kubernetes 原生资源。脚手架搭建项目按照 快速开始 先安装好 Kubebuilder然后创建一个新目录并初始化项目# create a project directory, and then run the init command. mkdir project cd project # This example uses a domain of tutorial.kubebuilder.io, # so all API groups is group.tutorial.kubebuilder.io. kubebuilder init --domain tutorial.kubebuilder.io --repo tutorial.kubebuilder.io/project两点值得注意项目名默认取当前工作目录名。可以通过--project-namedns1123-label-string指定不同的项目名。模块路径如果你在GOPATH内初始化项目隐式调用的go mod init会自动推断模块路径否则必须通过--repomodule path显式指定。从kubebuilder init生成的 PROJECT 文件可以看到本次脚手架使用的配置domain: tutorial.kubebuilder.io、layout: go.kubebuilder.io/v4、repo: tutorial.kubebuilder.io/project以及之后通过kubebuilder create api追加的resources条目groupbatch、kindCronJob、versionv1并开启defaulting与validation两种 webhook。这份元数据正是后续所有 scaffold 命令加 API、加 webhook能够正确插入代码的依据。基础项目里都有什么脚手架完成后Kubebuilder 为我们提供了一批基础样板go.mod与项目同名的新 Go 模块带有基础依赖。Makefile构建与部署控制器的 make 目标后续会用到的make manifests、make install、make run、make docker-build docker-push、make deploy都由它承载。PROJECTKubebuilder 用于继续脚手架新组件的元数据。启动配置集中在 config/ 目录目前只包含把控制器发布到集群所需的 Kustomize YAML 定义一旦开始编写控制器这里还会逐步放入 CRD、RBAC 配置与 Webhook 配置。其中config/default以标准配置启动控制器的 Kustomize basekustomization.yaml 负责把所有资源组装起来。其余每个目录都是独立拆出的配置 baseconfig/manager以 Pod 形式在集群内启动控制器。config/rbac控制器在其专属 ServiceAccount 下运行所需的权限。最后Kubebuilder 还脚手架出项目入口main.go。它目前相当简单注册 scheme、创建并启动 manager其中kubebuilder:scaffold:builder标记的位置会随教程推进逐渐被填入控制器与 webhook 的注册逻辑。术语准备Groups、Versions、Kinds 与 Resources在设计 API 之前先统一四个高频术语API Group一组相关功能的集合每个 group 有一个或多个version使 API 可以随时间演进。Kind某个 group-version 下的 API 类型。同一 Kind 在不同版本间形式可以不同但每个版本都必须能以某种方式字段或注解保存其他版本的全部数据从而保证使用旧版本 API 不会丢失或损坏新数据。ResourceKind 在 API 中的一种用法。通常 Kind 与 resource 一一对应如pods对应Pod但同一 Kind 也可能被多个 resource 返回如ScaleKind 同时由deployments/scale与replicasets/scale返回这正是 HorizontalPodAutoscaler 能与不同资源交互的原因。注意 resource 恒为小写按惯例是 Kind 的小写形式CRD 场景下每个 Kind 只对应一个 resource。GVK / GVR特定 group-version 下的 Kind 叫GroupVersionKindGVK资源同理叫 GVR。每个 GVK 对应包内一个根 Go 类型。Scheme 是什么之前见到的Scheme就是「哪个 Go 类型对应哪个 GVK」的登记表。例如把tutorial.kubebuilder.io/api/v1.CronJob{}标记为batch.tutorial.kubebuilder.io/v1group 下的CronJobKind 后给定 API server 发来的如下 JSON{ kind: CronJob, apiVersion: batch.tutorial.kubebuilder.io/v1, ... }就能据此构造出CronJob{}反向提交CronJob{}时也能正确查回 group-version。添加一个新 API创建新 Kind 及其控制器使用kubebuilder create apikubebuilder create api --group batch --version v1 --kind CronJob交互提示时对 Create Resource 与 Create Controller 均回答y。该命令首次针对某个 group-version 调用时会创建对应的目录本例创建 api/v1/ 目录对应batch.tutorial.kubebuilder.io/v1还记得最开始设置的--domain吗。同时为CronJobKind 新增 api/v1/cronjob_types.go 文件——以后每次用不同 kind 调用该命令都会追加对应新文件。脚手架出来的 空 API 结构 是标准样板定义CronJobSpec期望状态与CronJobStatus观察到的状态。Kubernetes 通过「用期望状态Spec去调和集群实际状态再记录观察结果Status」运转因此大多数功能对象都包含 spec 与 statusConfigMap之类不编码期望状态的类型除外。定义根类型CronJob含TypeMeta与ObjectMeta与CronJobList批量操作如 LIST 使用的 Kind。顶部注释// kubebuilder:object:roottrue与// kubebuilder:subresource:status被称为marker为 controller-tools代码与 YAML 生成器提供额外元数据前者告诉object生成器该类型代表一个 Kind从而生成runtime.Object接口实现后者为 CronJob 启用 status 子资源使其行为接近内置类型。init()中通过SchemeBuilder.Register(CronJob{}, CronJobList{})把类型注册进 API group。设计 CronJob 的 API字段序列化规则Kubernetes 对 API 设计有几条硬性规则所有序列化字段必须是camelCase因此要用 JSON struct tag 指定可以用omitempty标记字段为空时省略序列化。数值类型上整数接受int32与int64小数则使用resource.Quantity以保证 API 兼容性。Quantity 是什么Quantity 是十进制数的一种特殊记法具有明确固定的表示跨机器可移植——你在 Pod 的 resources requests/limits 里见到的就是它。它概念上类似浮点数有效数、基数、指数可序列化、可读的格式用「整数 后缀」表达就像描述计算机存储那样。例如2m表示十进制0.0022Ki表示十进制20482K表示2000要表达分数则切换到允许整数的后缀2.5写作2500m。支持两种基数10decimal使用常规 SI 后缀如M/K与 2binary使用 mebi 记法如Mi/Ki可类比「兆字节 vs 兆比字节」。另一个特殊类型是metav1.Time行为与time.Time一致但拥有固定、可移植的序列化格式。完整的 CronJob 类型定义以 cronjob_types.go 为准CronJobSpec的核心字段如下Schedule stringcron 格式的调度表达式// kubebuilder:validation:MinLength0、// required。StartingDeadlineSeconds *int64错过计划时间后允许延迟启动的秒数错过的执行会计为失败// optional、// kubebuilder:validation:Minimum0。ConcurrencyPolicy ConcurrencyPolicy并发执行策略合法值为Allow默认允许并发、Forbid禁止并发上一次未结束就跳过下一次、Replace取消正在运行的 Job 并用新 Job 替换。字段上带// kubebuilder:default:Allow自定义类型 ConcurrencyPolicy 本质是 string但通过// kubebuilder:validation:EnumAllow;Forbid;Replace把校验挂在类型上而非字段上更易复用。Suspend *bool挂起后续执行不影响已开始的执行默认 false。JobTemplate batchv1.JobTemplateSpec执行 CronJob 时要创建的 Job 模板// required。注意它直接复用 Kubernetes 内置batch/v1类型——这正是「与外部类型交互」的体现。SuccessfulJobsHistoryLimit / FailedJobsHistoryLimit *int32保留的成功/失败 Job 数量用指针区分「显式 0」与「未指定」均// kubebuilder:validation:Minimum0。CronJobStatus包含Active []corev1.ObjectReference当前运行中 Job 的引用列表// listTypeatomic且限制MinItems1、MaxItems10、LastScheduleTime *metav1.Time上次成功调度时间以及标准的Conditions []metav1.Condition// listTypemap、// listMapKeytype遵循 Kubernetes 状态条件惯例Available/Progressing/Degraded等。根类型CronJob与CronJobList的样板// kubebuilder:object:roottrue不需要改动唯一要做的调整就是加上// kubebuilder:subresource:status让状态更新走独立的 status 子资源。顺便认识另外两个文件如果翻看 api/v1/ 目录会发现除cronjob_types.go外还有两个文件它们都不需要手工编辑前者保持不变、后者自动生成但值得了解groupversion_info.go承载 group-version 的公共元数据。包级 marker// kubebuilder:object:generatetrue与// groupNamebatch.tutorial.kubebuilder.io分别供object生成器与 CRD 生成器使用随后定义SchemeGroupVersionschema.GroupVersion{Group: batch.tutorial.kubebuilder.io, Version: v1}、SchemeBuilder注册metav1.AddToGroupVersion以及便捷方法AddToScheme。zz_generated.deepcopy.goruntime.Object接口的自动生成实现用于把所有根类型标记为 Kind。其核心是深拷贝方法DeepCopyObjectcontroller-tools 的object生成器还会为每个根类型及其子类型额外生成DeepCopy与DeepCopyInto两个方法。控制器基础Reconciler 长什么样控制器是 Kubernetes 与任何 operator 的核心它的职责是确保「对于任意对象世界集群状态以及潜在的集群外状态如 Kubelet 的容器、云厂商的负载均衡器的实际状态」与对象中的期望状态一致。每个控制器专注于一个根 Kind但可以与其他 Kind 交互这个过程称为reconciling。在 controller-runtime 中针对特定 Kind 实现调和逻辑的单元是Reconciler它接收一个对象的名字返回是否需要重试例如出错时或像 HorizontalPodAutoscaler 这样的周期型控制器。脚手架生成的 空控制器 结构如下type CronJobReconciler struct { client.Client Scheme *runtime.Scheme } // kubebuilder:rbac:groupsbatch.tutorial.kubebuilder.io,resourcescronjobs,verbsget;list;watch;create;update;patch;delete // kubebuilder:rbac:groupsbatch.tutorial.kubebuilder.io,resourcescronjobs/status,verbsget;update;patch func (r *CronJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ logf.FromContext(ctx) // your logic here return ctrl.Result{}, nil } func (r *CronJobReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(batchv1.CronJob{}). Complete(r) }要点几乎所有 reconciler 都需要日志与拉取对象的能力因此开箱即带client.Client与Schemekubebuilder:rbac标记会被 controller-gen 生成到 config/rbac/role.yaml通过make manifests执行Reconcile返回空Result{}与nil表示「成功调和、在对象变化前无需重试」。controller-runtime 使用 logr 做结构化日志即「固定消息 键值对」。SetupWithManager把 reconciler 注册进 manager当前只声明监听CronJob稍后会用Owns声明关注相关对象。main.go 的演进脚手架生成的 空 main.go 大致做三件事解析基础 flagmetrics 地址、健康探针地址、leader election 开关、实例化 manager负责运行所有控制器、建立共享缓存与 API server 客户端并被告知我们的 Scheme、运行 manager 直至收到优雅退出信号在 Kubernetes 上表现为优雅的 Pod 终止。管理器还可以通过Cache: cache.Options{DefaultNamespaces: ...}把项目作用域限制到单个或一组 Namespace——注意此时也应把ClusterRole/ClusterRoleBinding换成Role/RoleBinding以收紧授权。写完 API 与控制器后完整的 main.go 发生了两处关键变化注册新 API group 到 schemeutilruntime.Must(batchv1.AddToScheme(scheme))把batchv1包加入 scheme控制器即可使用这些对象。内置类型如 Job由clientgoscheme负责若使用其他外部 CRD也需要同样方式添加其 scheme。注册控制器与 webhook在kubebuilder:scaffold:builder位置调用(controller.CronJobReconciler{Client: mgr.GetClient(), Scheme: mgr.GetScheme()}).SetupWithManager(mgr)随后通过os.Getenv(ENABLE_WEBHOOKS) ! false条件调用webhookv1.SetupCronJobWebhookWithManager(mgr)——这就是本地调试时用ENABLE_WEBHOOKSfalse关闭 webhook 的原理所在。其余部分metrics 安全服务、webhook server 的 TLS 选项、healthz/readyz 探针、leader election ID80807133.tutorial.kubebuilder.io均由脚手架默认提供。实现 CronJob 控制器完整实现见 internal/controller/cronjob_controller.go其基本逻辑分七步按名字加载 CronJobr.Get(ctx, req.NamespacedName, cronJob)若IsNotFound则说明对象已被删除直接停止调和。列出所有活跃 Job 并更新状态用r.List(ctx, childJobs, client.InNamespace(req.Namespace), client.MatchingFields{jobOwnerKey: req.Name})拉取属于该 CronJob 的子 Job——注意MatchingFields实际是走索引查询索引在 Setup 阶段建立见下。通过 Job 的状态条件判断是否「完成」Complete/Failed为 True把 Job 分为 active/successful/failed 三类并从 Job 上的scheduled-at注解重建LastScheduleTime用r.Status().Update写回 status 子资源。按历史上限清理旧 Job对 failed/successful 两类 Job 按StartTime稳定排序把超出FailedJobsHistoryLimit/SuccessfulJobsHistoryLimit的旧 Job 用client.PropagationPolicy(metav1.DeletePropagationBackground)删除。删除属于「尽力而为」失败不会因此触发重排队。检查是否挂起Spec.Suspend ! nil *cronJob.Spec.Suspend时直接返回不做任何调度。计算下一个调度时刻getNextSchedule用 robfig/cron 的cron.ParseStandard解析Schedule从LastScheduleTime或CreationTimestamp开始枚举错过的时间点若错过次数超过 100可能由时钟偏移导致则返回错误提示设置/调低spec.startingDeadlineSeconds。到点且未过期限、且未被并发策略拦截时运行新 Job错过时间点非零且仍在StartingDeadlineSeconds期限内才执行Forbid策略下若有活跃 Job 则跳过Replace策略下先删除所有活跃 Job随后constructJobForCronJob用确定性命名fmt.Sprintf(%s-%d, cronJob.Name, scheduledTime.Unix())构造 Job避免同一 Job 被创建两次复制 JobTemplate 的 spec 与 labels/annotations、写入scheduled-at注解、并通过ctrl.SetControllerReference设置 owner reference——这一步同时带来两个效果删除 CronJob 时垃圾回收器会清理 Jobcontroller-runtime 能据此在 Job 增删/完成时反查需要调和的 CronJob。最后r.Create(ctx, job)创建 Job。重排队返回ctrl.Result{RequeueAfter: nextRun.Sub(r.Now())}该值是「最迟重试期限」——期间若有 Job 开始/结束或对象被修改会触发更早的调和。可测的时钟为了便于测试控制器把时间抽象为Clock接口Now() time.Time生产环境用realClock{}直接调用time.Now。这样测试中可以注入假时钟在时间轴上快速跳转。状态条件Status Conditions控制器全程维护三个标准条件Available资源功能完好、Progressing正在创建/更新、Degraded未达到或无法维持期望状态。挂起时AvailableFalseReasonSuspended有失败 Job 时DegradedTrueReasonJobsFailed有活跃 Job 时ProgressingTrue且AvailableTrueReasonJobsActive全部完成后AvailableTrue、ProgressingFalseReasonAllJobsCompleted。Setup索引与 OwnsSetupWithManager做两件事注册字段索引mgr.GetFieldIndexer().IndexField(...)以jobOwnerKey .metadata.controller为索引键从 Job 的 controller owner 中提取「拥有它的 CronJob 名字」作为索引值。这是MatchingFields{jobOwnerKey: req.Name}能高效工作、避免每次全量过滤 Job 的原因。声明所有权ctrl.NewControllerManagedBy(mgr).For(batchv1.CronJob{}).Owns(kbatch.Job{}).Named(cronjob).Complete(r)告诉 manager 该控制器拥有 Job——Job 变化时会自动触发对底层 CronJob 的 Reconcile。RBAC 标记因为要创建和管理 JobRBAC 标记相比脚手架默认版本多了几条marker 语法详见 RBAC 标记文档// kubebuilder:rbac:groupsbatch.tutorial.kubebuilder.io,resourcescronjobs,verbsget;list;watch;create;update;patch;delete // kubebuilder:rbac:groupsbatch.tutorial.kubebuilder.io,resourcescronjobs/status,verbsget;update;patch // kubebuilder:rbac:groupsbatch.tutorial.kubebuilder.io,resourcescronjobs/finalizers,verbsupdate // kubebuilder:rbac:groupsbatch,resourcesjobs,verbsget;list;watch;create;update;patch;delete // kubebuilder:rbac:groupsbatch,resourcesjobs/status,verbsget运行与部署控制器如果对 API 定义做过修改先重新生成清单make manifests然后本地运行控制器。此前先安装 CRD会自动按需用 controller-tools 更新 YAML 清单make installToo long annotations 报错若应用 CRD 时因metadata.annotations超过 262144 字节限制而报错参见 FAQ 中的对应条目。安装 CRD 后即可本地运行控制器——它直接使用你连接集群的凭据因此暂时无需担心 RBACexport ENABLE_WEBHOOKSfalse make run本地运行 webhook若要在本地跑 webhook需要生成证书并放到默认目录/tmp/k8s-webhook-server/serving-certs/tls.{crt,key}若连接的是远程集群还得解决流量代理问题。因此本地「写码-运行-测试」循环建议按上面方式关闭 webhook。此时应能看到控制器启动日志暂时不会有实际动作。接下来写一个测试用 CronJob 样例对应 config/samples/batch_v1_cronjob.yamlapiVersion: batch.tutorial.kubebuilder.io/v1 kind: CronJob metadata: labels: app.kubernetes.io/name: project app.kubernetes.io/managed-by: kustomize name: cronjob-sample spec: schedule: */1 * * * * startingDeadlineSeconds: 60 concurrencyPolicy: Allow # explicitly specify, but Allow is also default. jobTemplate: spec: template: spec: securityContext: runAsNonRoot: true runAsUser: 1000 seccompProfile: type: RuntimeDefault containers: - name: hello image: busybox args: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: false restartPolicy: OnFailure创建并观察kubectl create -f config/samples/batch_v1_cronjob.yaml kubectl get cronjob.batch.tutorial.kubebuilder.io -o yaml kubectl get job此时应能看到 CronJob 运行并持续更新 status。确认工作正常后停掉make run部署进集群make docker-build docker-push IMGsome-registry/project-name:tag make deploy IMGsome-registry/project-name:tagRegistry 权限镜像应发布到你有权限的个人 registry且运行环境需能拉取该镜像失败时请确认 registry 权限。使用 Kind 可显著加速本地开发与 CIKind 集群无需推送到远端 registry直接kind load docker-image your-image-name:tag --name your-kind-cluster-name即可。RBAC 报错若遇到 RBAC 错误可能需要为自己授予 cluster-admin 权限或以 admin 登录常见于 GKE v1.11.x 及更早版本。实现默认与校验 Webhook如果希望为 CRD 接入 admission webhook唯一要做的就是实现admission.Defaulter与或admission.Validator接口——其余事情创建 webhook server、把 server 加进 manager、为 webhook 创建 handler、把每个 handler 注册到 server 的某个路径都由 Kubebuilder 代劳。先用脚手架命令生成 webhook本教程的测试项目同时用了 defaulting 与 validating 两种 webhookkubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation该命令会脚手架出 webhook 函数并在main.go中把 webhook 注册进 manager。自定义 webhook 路径kubebuilder create webhook支持用--defaulting-path与--validation-path指定自定义 HTTP 路径# Custom path for defaulting webhook kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --defaulting-path/my-custom-mutate-path # Custom path for validation webhook kubebuilder create webhook --group batch --version v1 --kind CronJob --programmatic-validation --validation-path/my-custom-validate-path # Both webhooks with different custom paths kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation \ --defaulting-path/custom-mutate --validation-path/custom-validate这只会改变 webhook marker 注解中的路径不改变文件生成位置——webhook 文件仍会生成在internal/webhook/v1/。版本要求自定义路径需要controller-runtime v0.21。更早版本v0.21中路径必须遵循特定模式按资源的 group/version/kind 自动生成如/mutate-batch-v1-cronjob无法自定义。实现细节完整实现见 internal/webhook/v1/cronjob_webhook.go。注册SetupCronJobWebhookWithManager通过ctrl.NewWebhookManagedBy(mgr, batchv1.CronJob{}).WithValidator(...).WithDefaulter(...).Complete()完成注册。Defaulter 携带可配置的默认值DefaultConcurrencyPolicy: batchv1.AllowConcurrent、DefaultSuspend: false、DefaultSuccessfulJobsHistoryLimit: 3、DefaultFailedJobsHistoryLimit: 1。Mutating webhook// kubebuilder:webhook:path/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutatingtrue,...标记负责生成变更 webhook 清单。CronJobDefaulter.Default通过applyDefaults为未设置字段空字符串的 ConcurrencyPolicy、nil 的 Suspend 与两个历史上限填充默认值。Validating webhook// kubebuilder:webhook:path/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutatingfalse,...标记负责生成校验 webhook 清单。CronJobValidator实现ValidateCreate/ValidateUpdate/ValidateDeleteCreate 与 Update 共用validateCronJobDelete 不做校验validateScheduleFormat直接用cron.ParseStandard校验 cron 表达式是否格式良好避免手写长正则validateCronJobName校验名字不超过 52 字符——因为控制器创建 Job 时会追加 11 字符的-$TIMESTAMP后缀而 Job 名最长 63 字符DNS 子域限制若在此处不校验后续创建 Job 必然失败。两个 webhook 结构体都带// kubebuilder:object:generatefalse标记阻止 controller-gen 为它们生成 DeepCopy 方法它们只用于临时操作无需深拷贝。更完整的校验 marker 列表可在声明式校验章节api-design.md与 CRD 校验 marker 文档 中查看。部署 Webhook 到集群安装 cert-managerwebhook 证书由 cert-manager。构建镜像make docker-build docker-push IMGsome-registry/project-name:tagKind 用户同样可以直接kind load docker-image your-image-name:tag --name your-kind-cluster-name而无需推送。启用 webhook 的 Kustomize 配置需要取消 config/default/kustomization.yaml 中 webhook 相关段落的注释Resources加入 webhook 与 cert-manager 资源- ../webhook与- ../certmanagerPatches加入 webhook manager patch- path: manager_webhook_patch.yamltarget 为 DeploymentReplacements加入 webhook 证书替换把 webhook-service 的 name/namespace 替换进serving-certCertificate 的spec.dnsNames并把 Certificate 的 namespace/name 拼成cert-manager.io/inject-ca-from注解注入 Mutating/ValidatingWebhookConfigurationdelimiter: /。同时 config/crd/kustomization.yaml 需要启用带cert-manager.io/inject-ca-from注解的 CA 注入补丁。随后部署make deploy IMGsome-registry/project-name:tag等待 webhook Pod 起来、证书签发完成通常 1 分钟内。然后创建合法 CronJob 应成功通过kubectl create -f config/samples/batch_v1_cronjob.yaml再尝试创建非法 CronJob例如 schedule 字段格式错误应看到带校验错误的创建失败。启动自举问题Bootstrapping Problem把 webhook 部署进它自己将校验的集群时webhook 可能在自身 Pod 运行前就去校验该 Pod 的创建从而阻塞自己启动。规避方式让 webhook忽略自己的资源——要么用namespaceSelector给 webhook 所在 namespace 打标签并在配置中跳过它要么用objectSelector给 webhook 自己的 Pod/Deployment 打标签并直接排除。完整分步指南见 Webhook Bootstrap Problem。编写控制器测试测试 Kubernetes 控制器是个大主题Kubebuilder 生成的样板测试文件相对精简。kubebuilder create api时已生成 internal/controller/suite_test.go思路是用envtest启动本地 Kubernetes API server实例化并运行控制器再用 Ginkgo。测试环境搭建suite_test.go 的关键内容BeforeSuite中把batchv1.AddToScheme(scheme.Scheme)加入 runtime scheme配置envtest.Environment{CRDDirectoryPaths: []string{filepath.Join(.., .., config, crd, bases)}, ErrorIfCRDPathMissing: true}加载本地 CRDtestEnv.Start()启动集群client.New(cfg, client.Options{Scheme: scheme.Scheme})创建测试 CRUD 客户端。自动生成文件缺的是「真正启动控制器」需要在BeforeSuite里补 manager 逻辑与项目main.go几乎一致只是 manager 在独立 goroutine 中启动避免阻塞 envtest 清理。客户端选择断言时使用「live」k8s client直连 API server而 reconciler 仍跑在 manager 的 cache client 上——这样测试断言的是 API server 实时状态而非缓存缓存断言更慢且易抖动控制器则保持生产行为依赖 cache 的索引等能力。getFirstFoundEnvTestBinaryDir()帮助 IDE 直跑测试时定位 envtest 二进制等价于设置KUBEBUILDER_ASSETS环境变量二进制由make setup-envtest准备。AfterSuite中cancel()并testEnv.Stop()清理环境。行为测试cronjob_controller_test.go 演示了「自定义 Kind 下游对象」的通用测试策略构造测试桩BeforeEach创建 Namespace 与 CronJob CR注意必须带上 JobTemplateSpec 与 PodTemplateSpec 桩否则 API server 拒绝创建。验证状态初始化Eventually断言cronJob.Status.Conditions非空控制器后台检测到 CronJob 并初始化条件再用Consistently10 秒超时、250ms 轮询断言Status.Active为空确认控制器不会提前建 Job。创建带 owner reference 的 Job用metav1.NewControllerRef(cronJob, gvk)设置 owner需要cronjobv1.GroupVersion.WithKind(kind)得到 GVK创建后通过k8sClient.Status().Update把testJob.Status.Active 2status 必须在创建后单独更新。断言状态联动Eventually断言Status.Active长度 1 且名字为test-job并断言存在AvailableTrue且 Reason 为JobsActive的状态条件。验证历史清理设置FailedJobsHistoryLimit/SuccessfulJobsHistoryLimit为 1用createFinishedJob创建两旧两新按 StartTime 区分的 failed/successful Job最终Eventually断言旧的被删除、新的保留。运行测试make test或go test ./...。延伸阅读完整示例工程docs/book/src/cronjob-tutorial/testdata/project教程章节索引cronjob-tutorial.md快速开始与安装quick-start.mdKind 本地开发工作流reference/kind.mdRBAC / Webhook / CRD 校验 marker 语法reference/markers/rbac.md、reference/markers/webhook.md、reference/markers/crd-validation.mdenvtest 集成测试reference/envtest.mdWebhook 自举问题reference/webhook-bootstrap-problem.md赞分享开发者工具代码生成CLI云原生后端【免费下载链接】kubebuilderKubebuilder - SDK for building Kubernetes APIs using CRDs项目地址https://gitcode.com/gh_mirrors/ku/kubebuilder点击查看免费下载相关推荐实战使用Kubebuilder构建CRD控制器实战使用Kubebuilder构建CRD控制器 本文详细介绍了使用Kubebuilder框架构建Kubernetes CRD控制器的完整流程包括项目初始化与开发者工具代码生成CLI云原生后端用Kubebuilder构建CronJob Operator从CRD定义到集群部署的完整教程用Kubebuilder构建CronJob Operator从CRD定义到集群部署的完整教程 Kubebuilder 是 Kubernetes 官方推荐的 C开发者工具代码生成CLI云原生后端使用 kubebuilder 从零构建 Kubernetes OperatorGuestbook 实战指南使用 kubebuilder 从零构建 Kubernetes OperatorGuestbook 实战指南 本篇指南以 Kubernetes Handbook教程云原生容器编排上一篇TW-Elements性能瓶颈分析常见问题与解决方案下一篇终极React Native应用安全编码指南防范10种常见攻击创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表