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

Posted LanYuLei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubebuilder 实战之开发一个存储用户信息的 operator相关的知识,希望对你有一定的参考价值。

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

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

开发环境准备

初始化 kubebuilder

mkdir lanyulei
cd lanyulei
kubebuilder 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 User

Create Resource [y/n] # 是否创建资源对象
y
Create Controller [y/n] # 是否创建 controller
y
  • --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 User
type 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:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile
func (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


// 创建 ServiceAccount
func (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 <sub>]# kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
cert-manager cert-manager-64d9bc8b74-ptl4n 1/1 Running 0 149m
cert-manager cert-manager-cainjector-6db6b64d5f-xcw2d 1/1 Running 0 149m
cert-manager cert-manager-webhook-6c9dd55dc8-wk8lw 1/1 Running 0 149m
kube-system coredns-64897985d-wtcqq 1/1 Running 0 15h
kube-system coredns-64897985d-x8g7s 1/1 Running 0 15h
kube-system etcd-karmada-work-2-control-plane 1/1 Running 0 15h
kube-system kindnet-8wcr6 1/1 Running 0 15h
kube-system kube-apiserver-karmada-work-2-control-plane 1/1 Running 0 15h
kube-system kube-controller-manager-karmada-work-2-control-plane 1/1 Running 0 15h
kube-system kube-proxy-5w2ln 1/1 Running 0 15h
kube-system kube-scheduler-karmada-work-2-control-plane 1/1 Running 0 15h
local-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 </sub>]#

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

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

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

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

 本文为原创文章,未经授权禁止转载本站文章。

 原文出处:兰玉磊的个人博客

 原文链接:https://www.fdevops.com/2022/04/10/kubebuilder-crd-31074

 版权:本文采用「署名-非商业性使用-相同方式共享 4.0 国际」知识共享许可协议进行许可。

以上是关于kubebuilder 实战之开发一个存储用户信息的 operator的主要内容,如果未能解决你的问题,请参考以下文章

kubebuilder笔记

大数据实战之千万量级小说网站项目开发(存储复杂搜索推荐分析)

深入解析 Kubebuilder:让编写 CRD 变得更简单

Java实战之04JavaWeb-03会话技术

UEFI实战HII之配置

UEFI实战HII之配置