求助:如何开始为Custom Resource创建Custom Controller?
自定义控制器与自定义资源入门指南
一、先搞懂Custom Resource(CR)能做什么
- 扩展Kubernetes的API体系,让你定义专属的资源类型(比如
RedisCluster、MyBusinessApp),和K8s内置的Deployment、Pod一样,用kubectl命令统一管理 - 把业务逻辑抽象成K8s资源对象,比如你可以定义一个
DatabaseClusterCR,指定副本数、存储容量,由控制器自动帮你创建对应的StatefulSet、PersistentVolumeClaim、Service等资源 - 统一业务与K8s生态的管理方式,用
kubectl apply提交业务配置,用kubectl get查看业务状态,不需要单独维护一套业务管理工具
二、从零开始的启动步骤
1. 定义Custom Resource Definition(CRD)
这是第一步,先告诉K8s你的自定义资源是什么结构。创建一个crd.yaml文件:
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: myapps.example.com spec: group: example.com versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: replicas: type: integer image: type: string scope: Namespaced names: plural: myapps singular: myapp kind: MyApp shortNames: - ma
执行kubectl apply -f crd.yaml提交到集群,之后你就能像操作内置资源一样创建MyApp类型的CR了。
2. 编写控制器Go代码(核心逻辑)
控制器的核心是监听CR的变化,执行对应业务逻辑,推荐用K8s官方的controller-runtime框架(简化开发流程),核心流程如下:
- 初始化K8s客户端:本地开发用
~/.kube/config连接集群,集群内部署用ServiceAccount自动认证 - 注册要监听的CR类型,设置控制器的调和(Reconcile)逻辑
- 实现
Reconcile函数:这是控制器的核心入口,CR创建/更新/删除时都会触发,你在这里写具体的业务逻辑(比如根据CR的spec创建Deployment)
示例Reconcile函数片段:
func (r *MyAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // 1. 获取目标MyApp实例 var myapp examplev1.MyApp if err := r.Get(ctx, req.NamespacedName, &myapp); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } // 2. 检查对应的Deployment是否存在,不存在则创建 var deploy appsv1.Deployment deployName := myapp.Name err := r.Get(ctx, types.NamespacedName{Name: deployName, Namespace: myapp.Namespace}, &deploy) if err != nil && apierrors.IsNotFound(err) { // 构造Deployment对象 deploy = appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: deployName, Namespace: myapp.Namespace, }, Spec: appsv1.DeploymentSpec{ Replicas: &myapp.Spec.Replicas, Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{ { Name: "myapp", Image: myapp.Spec.Image, }, }, }, }, }, } if err := r.Create(ctx, &deploy); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil } // 3. 如果Deployment副本数与CR不一致,更新Deployment if *deploy.Spec.Replicas != myapp.Spec.Replicas { deploy.Spec.Replicas = &myapp.Spec.Replicas if err := r.Update(ctx, &deploy); err != nil { return ctrl.Result{}, err } } return ctrl.Result{}, nil }
3. 运行控制器的两种方式
- 本地开发调试:
确保本地有kubeconfig文件(默认在~/.kube/config),直接运行Go程序:go run main.go,控制器会自动连接到你的K8s集群(minikube、远程集群都可以) - 部署到K8s集群:
- 把控制器代码打包成Docker镜像,推送到镜像仓库
- 创建Deployment运行控制器,同时创建ServiceAccount并分配必要权限(比如读取MyApp、创建Deployment的权限)
示例Deployment片段:
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-controller spec: replicas: 1 selector: matchLabels: app: myapp-controller template: metadata: labels: app: myapp-controller spec: serviceAccountName: myapp-controller-sa containers: - name: controller image: your-registry/myapp-controller:v1 args: - --metrics-addr=127.0.0.1:8080 - --enable-leader-election
4. 测试验证
创建一个myapp-sample.yaml:
apiVersion: example.com/v1 kind: MyApp metadata: name: myapp-sample spec: replicas: 2 image: nginx:latest
执行kubectl apply -f myapp-sample.yaml,然后用kubectl get deploy检查是否自动创建了对应副本数的Deployment;修改CR的replicas值,再看Deployment是否同步更新。
三、关键切入点总结
- 先完成CRD定义,确保自定义资源能被K8s正确识别
- 基于
controller-runtime搭建控制器基础结构,重点实现Reconcile函数的业务逻辑 - 本地调试验证逻辑正确性后,再打包部署到集群
- 逐步扩展功能,比如处理资源删除、错误重试、状态更新等
内容的提问来源于stack exchange,提问作者Deepak singh
相关产品推荐
相关产品推荐

