基于operator-sdk的kubernetes-operator实现

目录

简介

本文基于operator-sdk,实现一个简单的operator,一方面学习和了解operator,另一方面通过该operator实现一个简单的功能:对于符合名称前缀的一系列命名空间,约束某些命名空间的deployment replica为0,仅允许白名单里的namespace有pod运行。

实现该自动化的动机是:在工作中由于集群资源有限,且开发中的项目版本众多,每个版本都在各自的命名空间运行,大量的pod可能未在使用。在交付发布前,需要优先保证待发布版本的命名空间能够有足够的资源运行pod,避免因为各种resource不足导致的调度失败。在没有该operator时,需要每次发布前挑选版本,然后逐个运行kubectl scale命令将命名空间内的deploy全部缩为0。

本文仓库地址:lwabish/namespace-scaler-operator: 按照参数配置,把在管理范围内且不在白名单内的namespace下的deployment全部scale为0 (github.com)

准备工作

  1. 安装operator-sdk:Installation | Operator SDK (operatorframework.io)

  2. 初始化项目:operator-sdk init --domain wubw.fun --repo github.com/lwabish/namespace-scaler-operator

  3. 创建指定GVK(Group Version Kind)的crd和控制器,本文的cr kind为NSScaler:operator-sdk create api --group operators --version v1alpha1 --kind NSScaler --resource --controller --namespaced=false

  4. 修改cr的spec结构体api/v1alpha1/nsscaler_types.go,按需增加字段,然后make generate用代码生成器生成深拷贝之类的代码。

  5. 生成crd yaml:make manifests

控制器实现

controllers/nsscaler_controller.go为控制器,需要我们实现协调循环函数Reconcile

触发

  1. 首先,我们的cr在创建、更新、删除时,控制器显然是需要调用Reconcile函数进行状态协调的。
  2. 其次,如果operator会创建附属于operator的子资源,那么这些子资源的状态发生变更时也应该调用Reconcile函数进行协调。如果是这种情况需要参考文档增加子资源类型。

父子关系

如果operator会创建子资源,那么需要在创建后标记出父子关系:controllerutil.SetControllerReference()

增删改查

控制器结构体组合了一个专门为控制器准备的k8s client,可以用该client从cache中高效地增删改查集群对象,作为完成逻辑的基础。

// 基本逻辑先创建实例,然后把指针传给r.Get/List/Update等方法,最后获取结果
func (r *NSScalerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  ...
  // 查
  instance := &operatorsv1alpha1.NSScaler{}
	err := r.Get(ctx, req.NamespacedName, instance)
  
  // 批量查
  nsList := &coreV1.NamespaceList{}
	err = r.List(ctx, nsList, &client.ListOptions{})
  
  // 改
  err = r.Update(ctx, &deployment, &client.UpdateOptions{})
}

状态维护

instance.Status.Done = noPodObserved
err = r.Status().Update(context.TODO(), instance)

幂等性

幂等性十分关键。确保每次调用协调循环完成的任务都是独立的,不依赖于其他操作的状态。

协调结果

// 有错
return ctrl.Result{}, err

// 没错,需要再次协调
return ctrl.Result{Requeue: true}, nil

// 正常结束
return ctrl.Result{}, nil

// 延时再次协调
return ctrl.Result{RequeueAfter: nextRun.Sub(r.Now())}, nil

本地调试

  1. make install/make uninstall 安装卸载crd到kubeconfig中的集群。

  2. make run启动控制器或使用idea/goland等debug main.go 启动控制器。

  3. kubectl apply -f config/samples/xxx.yaml 部署cr,观察控制器被触发后的效果。

集群部署

  1. 修改makefile中的IMAGE_TAG_BASEIMG ?= $(IMAGE_TAG_BASE):$(VERSION), 并设置合适的版本号version
  2. 国内网络即使宿主机可以连接k8s.io,在多阶段构建时容器里也无法直连k8s.io下载依赖。因此需要设置go proxy。Dockerfile中增加ENV GOPROXY="https://goproxy.cn,direct"
  3. build、push镜像:make docker-build docker-push
  4. 准备rbac相关的权限yaml。偷懒可直接在config/rbac/role_binding.yaml中把sa关联cluster-admin。
  5. make deploy

集群卸载

make undeploy

参考

Go Operator Tutorial | Operator SDK (operatorframework.io)

上一篇:【Redis专题】linux下安装redis


下一篇:Make 命令教程