kubebuilder 实战之开发一个存储用户信息的 operator

网友投稿 281 2022-09-28

kubebuilder 实战之开发一个存储用户信息的 operator

本文介绍如何使用 kubebuilder 实现一个存储用户信息的 CRD,同时开发 controller 绑定同名的 ServiceAccount。

不过多介绍 kubebuilder 的理论知识,直接开干。

开发环境准备

初始化 kubebuilder

mkdir lanyuleicd lanyuleikubebuilder init --domain lanyulei.com --repo lanyulei

init:初始化命令参数。--domain:可以理解为接口组的分组。根据实际情况来定,我一般定义为​​项目名.com​​。--repo:项目名称,若是当前项目下已经存在 go.mod,则无需此参数。

初始化成功后的代码结构。

.├── Dockerfile├── Makefile├── PROJECT├── config│ ├── default│ │ ├── kustomization.yaml│ │ ├── manager_auth_proxy_patch.yaml│ │ └── manager_config_patch.yaml│ ├── manager│ │ ├── controller_manager_config.yaml│ │ ├── kustomization.yaml│ │ └── manager.yaml│ ├── prometheus│ │ ├── kustomization.yaml│ │ └── monitor.yaml│ └── rbac│ ├── auth_proxy_client_clusterrole.yaml│ ├── auth_proxy_role.yaml│ ├── auth_proxy_role_binding.yaml│ ├── auth_proxy_service.yaml│ ├── kustomization.yaml│ ├── leader_election_role.yaml│ ├── leader_election_role_binding.yaml│ ├── role_binding.yaml│ └── service_account.yaml├── go.mod├── go.sum├── hack│ └── boilerplate.go.txt└── main.go

开启支持多接口组

如果你本次项目开发的 ​​operator​​​ 是​​多接口组​​的话,则需要执行一下命令。

例如:同时需要​​用户相关接口​​​和​​角色相关接口​​​,则需要​​两组 api group​​,因此需要执行以下操作。

kubebuilder edit --multigroup=true

需要的工具

这三个工具是需要提前下载好的,放在项目的根目录下的 ​​bin​​ 目录下面的。

controller-gen (Version: v0.8.0)kustomize (Version: v4.5.4)setup-envtest (Version: latest)

Github 下载对应系统的二进制文件即可,版本的话,我测试的版本已标注,根据实际情况自行调整版本即可。

注意:工具下载完后,放到 ​​bin​​ 目录后,后面操作才可正常执行。

创建 API

执行以下命令创建我们需要 ​​api group​​。

$ kubebuilder create api --group user --version v1 --kind UserCreate Resource [y/n] # 是否创建资源对象yCreate Controller [y/n] # 是否创建 controllery

--group:接口分组--version:接口版本--kind:对应 k8s 资源对象中的 kind

创建接口组后的代码结构

.├── Dockerfile├── Makefile├── PROJECT├── apis│ └── user # 用户接口组│ └── v1│ ├── groupversion_info.go│ ├── user_types.go│ └── zz_generated.deepcopy.go├── bin # 常用工具目录│ ├── controller-gen│ ├── kustomize│ └── setup-envtest├── config│ ├── crd│ │ ├── kustomization.yaml│ │ ├── kustomizeconfig.yaml│ │ └── patches│ │ ├── cainjection_in_users.yaml│ │ └── webhook_in_users.yaml│ ├── default│ │ ├── kustomization.yaml│ │ ├── manager_auth_proxy_patch.yaml│ │ └── manager_config_patch.yaml│ ├── manager│ │ ├── controller_manager_config.yaml│ │ ├── kustomization.yaml│ │ └── manager.yaml│ ├── prometheus│ │ ├── kustomization.yaml│ │ └── monitor.yaml│ ├── rbac│ │ ├── auth_proxy_client_clusterrole.yaml│ │ ├── auth_proxy_role.yaml│ │ ├── auth_proxy_role_binding.yaml│ │ ├── auth_proxy_service.yaml│ │ ├── kustomization.yaml│ │ ├── leader_election_role.yaml│ │ ├── leader_election_role_binding.yaml│ │ ├── role_binding.yaml│ │ ├── service_account.yaml│ │ ├── user_editor_role.yaml│ │ └── user_viewer_role.yaml│ └── samples│ └── user_v1_user.yaml├── controllers # controller 管理│ └── user│ ├── suite_test.go│ └── user_controller.go├── go.mod├── go.sum├── hack│ └── boilerplate.go.txt└── main.go

代码实现

定义用户字段

通过完善 ​​Spec​​​ 后缀的结构体,来完善 k8s 中资源对象对应的 ​​spec​​ 字段。

我们在这里加上用户相关的字段描述。

apis/user/v1/user_types.go

// UserSpec defines the desired state of Usertype UserSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file // Nickname 用户名 Nickname string `json:"nickname,omitempty"` // Password 密码 Password string `json:"password,omitempty"` // Email 邮箱地址 Email string `json:"email,omitempty"` // Tel 手机号 Tel string `json:"tel,omitempty"` // IsAdmin 是否超级管理员 IsAdmin string `json:"is_admin,omitempty"` // IsActive 是否可用 IsActive string `json:"is_active,omitempty"`}

controller 开发

此部分开发,主要是绑定 ​​ServiceAccount​​。

在创建 ​​User​​​ 的时候,则创建对应同名的 ​​ServiceAccount​​,删除亦同理。

为方便统一管理,将 ​​ServiceAccount​​​ 统一存放在 ​​lanyulei_users​​ 的命名空间中。

kubebuilder 帮我们实现了大部分功能,因此我们只需要实现 ​​Reconcile​​​ 函数即可,​​req​​​ 会返回当前变更的对象的 ​​Namespace​​​ 和 ​​Name​​ 信息,有这两个信息,我们就可以获取到这个对象了,进行处理了。

controllers/user/user_controller.go

//+kubebuilder:rbac:groups=user.lanyulei.com,resources=users,verbs=get;list;watch;create;update;patch;delete//+kubebuilder:rbac:groups=user.lanyulei.com,resources=users/status,verbs=get;update;patch//+kubebuilder:rbac:groups=user.lanyulei.com,resources=users/finalizers,verbs=update//+kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;create;delete # 添加此项注释,表示为当前 controller 可对 ServiceAccount 进行 get、list、create、delete 操作。// Reconcile is part of the main k8s reconciliation loop which aims to// move the current state of the cluster closer to the desired state.// TODO(user): Modify the Reconcile function to compare the state specified by// the User object against the actual cluster state, and then// perform operations to make the cluster state reflect the state specified by// the user.//// For more details, check Reconcile and its Result here:// - (r *UserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // 判断同名 ServiceAccount 是否存在 sa := &corev1.ServiceAccount{} saReq := ctrl.Request{ NamespacedName: types.NamespacedName{ Namespace: UserNamespace, Name: req.Name, }, } err := r.Get(ctx, saReq.NamespacedName, sa) if errors.IsNotFound(err) { err := r.createServiceAccountIfNotExists(ctx, req) if err != nil { return ctrl.Result{}, err } } return ctrl.Result{}, nil}// 创建 ServiceAccountfunc (r *UserReconciler) createServiceAccountIfNotExists(ctx context.Context, req ctrl.Request) (err error) { logger := log.Log.WithValues("func", "createServiceAccountIfNotExists") logger.Info("start create service account.") user := &userv1.User{} err = r.Get(ctx, req.NamespacedName, user) if err != nil { logger.Error(err, "Failed to get user.") return } sa := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: req.Name, Namespace: UserNamespace, }, } // 绑定对应的sa,删除的时候连带着删除 err = controllerutil.SetControllerReference(user, sa, r.Scheme) if err != nil { logger.Error(err, "SetControllerReference error") return } err = r.Create(ctx, sa) if err != nil { logger.Error(err, "create service account error") return } return}

上面的代码中,我们看到了好多 ​​//+kubebuilder​​​ 这种格式的注释,此类注释是为了实现​​代码生成​​而添加的注释,此类内容较多,可通过搜索引擎,进行了解即可。

部署

首先我们需要本地需要有 ​​kubectl​​​ 命令,并且可以连接到 ​​k8s​​​ 集群。如果满足这个条件,那么我们就可以部署测试我们的 ​​operator​​ 了。

将 crd 部署到 k8s 集群上。

kubebuilder 帮我们写好了 ​​Makefile​​​ 如果没有定制化的需求,例如指定 k8s 集群配置文件,则直接执行下面的命令即可,若是有此类需求,还请自行调整 ​​Makefile​​。

部署 crd 到 k8s 集群

make install

本地启动 controller

make run

controller 部署到 k8s 集群运行

前面我们在开发环境将 controller 运行起来尝试了所有功能,在实际生产环境中,controller 并非这样独立于 k8s 之外,而是以 pod 的状态运行在 k8s 之中,接下来我们尝试将 controller 代码编译构建成 docker 镜像,再在k8s上运行起来。

首先你需要有一个 docker hub 的账号,然后使用 ​​docker login​​ 命令进行登陆。

执行下面的命令构建镜像并推送到 docker hub。

make docker-build docker-push IMG=lanyulei/lanyulei:v1.0.0

若推送网速过慢,可自行配置​​阿里云容器镜像加速器​​。

镜像准备好之后,执行以下命令即可在 k8s 集群中部署 controller。

make deploy IMG=lanyulei/lanyulei:v1.0.0

验证部署结果。

[root@karmada-work-1 ]# kubectl get po -ANAMESPACE NAME READY STATUS RESTARTS AGEcert-manager cert-manager-64d9bc8b74-ptl4n 1/1 Running 0 149mcert-manager cert-manager-cainjector-6db6b64d5f-xcw2d 1/1 Running 0 149mcert-manager cert-manager-webhook-6c9dd55dc8-wk8lw 1/1 Running 0 149mkube-system coredns-64897985d-wtcqq 1/1 Running 0 15hkube-system coredns-64897985d-x8g7s 1/1 Running 0 15hkube-system etcd-karmada-work-2-control-plane 1/1 Running 0 15hkube-system kindnet-8wcr6 1/1 Running 0 15hkube-system kube-apiserver-karmada-work-2-control-plane 1/1 Running 0 15hkube-system kube-controller-manager-karmada-work-2-control-plane 1/1 Running 0 15hkube-system kube-proxy-5w2ln 1/1 Running 0 15hkube-system kube-scheduler-karmada-work-2-control-plane 1/1 Running 0 15hlocal-path-storage local-path-provisioner-5ddd94ff66-fkw28 1/1 Running 0 15h# 这个就是我们部署的 controller, 2/2 表示容器运行中了。lanyulei-system lanyulei-controller-manager-7cb9cd6565-8wst8 2/2 Running 0 96m[root@karmada-work-1 ]#

查看日志,确认程序是否正常启动了。

kubectl logs -f \lanyulei-controller-manager-7cb9cd6565-8wst8 \-c manager \-n lanyulei-system

没有 Error 日志,则表示 controller 正常启动了,可以处理请求了。

自此我们开发,存储管理用户信息的 ​​​operator​​​ 就开发完成,可以通过 ​​postman​​, 测试接口的增删改查。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java 线程池存在的意义
下一篇:焱融看|AI 如何驱动存储发展
相关文章

 发表评论

暂时没有评论,来抢沙发吧~