Kubebuilder 使用记录

operator 介绍

(1)不同应用平台需要管理的目标各有差异,如何在 Kubernetes 中兼容定义管理的
目标?
(2)如何管理和备份系统的应用数据,协调各应用之间不同生命周期的状态?
(3)能否用同样的 Kubectl 命令来管理自己定义的复杂分布式应用?

在这些场景下,Kubernetes 自身基础模型已经无法支撑不同业务领域下的自动化场景。为了满足这些需求,谷歌提出了 Third Party Resources(TPR)概念,允许开发者根据业务需求的变化自定义资源和控制器,用于编写面向领域知识的业务逻辑控制,这就是Operator 的核心概念(后来 Kubernetes 使用 CRD 替代了 TPR,这两种机制除了名称,其他方面并没有什么变化)。

Operator 是 一 种 封 装、 部 署 和 管 理 Kubernetes 应 用 的 方 法, 用 户 可 以 使 用 Kubernetes API 和 Kubectl 工 具 在 Kubernetes 上 部 署 并 管 理 Kubernetes 应 用。Operator 基于基本 Kubernetes 资源和控制器概念构建,但又涵盖了特定领域或应用的知识,用于实现其所管理软件的整个生命周期的自动化,它是一种特定于应用的控制器,可扩展 Kubernetes API 的功能,是 Kubernetes 用户创建、配置和管理复杂应用的实例。

简单来说 Operator=Controller+CRD,Operator 是由 Kubernetes 自定义资源(CRD)和控制器(Controller)构成的云原生᠀展服务,其中 CRD 定义了每个 Operator 需要创建和管理的自定义资源对象,底层实际就是通过 APIServer 接口在 ETCD 中注册一种新的资源类型,注册完成后就可以创建该资源类型的对象了。但是仅注册资源和创建资源对象是没有任何实际意义的,CRD 最重要的是需要配合对应的 Controller 来实现自定义资源的功能,达到自定义资源期望的状态,比如内置的 Deployment Controller 用来控制 Deployment 资源的功能,根据配置生成特定数量的 Pod 监控其状态,并根据事件做出相应的动作。

在这里插入图片描述

用户想为自己的自定义资源构建一个 Kubernetes Operator,有很多工具可供选择,比如 Operator SDK、Kubebuilder,甚至可以使用 Operator SDK(Helm、Ansible、Go)

本文介绍 Kubebuilder,operator-sdk 可自行学习。


Kubebuilder

Kubebuilder 是一个帮助开发者快速开发 Kubernetes API 的脚手架命令行工具,依赖 Controller-tool 和 Controller-runtime 等库,简化 Kubernetes Controller 的开发,并且对 Kubernetes 的几个常用库进行了封装。

Kubebuilder 的整体工作流程如下:

(1)初始化一个新的工程目录。
(2)创建一个或多个资源 API CRD,然后将字段添加到资源。
(3)在控制器中实现协调循环(Reconcile Loop),监听额外的资源。
(4)在集群中运行测试(自动安装 CRD 并自动启动控制器)。
(5)更新引导测试新字段和业务逻辑。
(6)生产环境使用 Dockerfile 构建和发布容器。

在这里插入图片描述


实操手册

安装

git clone https://gitee.com/henrywangx/kubebuilder.git
cd kubebuilder
make build
cp bin/kubebuilder $GOPATH/bin

源码安装,速度不会比直接去 GitHub 上拉取成品要慢。

如果是跟着我的系列走到这里,默认是有 go 环境的。

export GO111MODULE=on
export GOPROXY=https://goproxy.io

kustomize 也是要安装一下的,搜一下 git 上的官网,直接下载成品也就几个 M,加个执行权限,然后放到 /usr/local/bin 目录下去。


创建project

mkdir $GOPATH/src/demo
cd $GOPATH/src/demo
kubebuilder init --domain demo.com --license apache2 --owner "xiong"

如果说第三步报错,就换到正常 home 下的个人目录里,再走一遍。

这里kubebuilder帮我们生成了一下模板文件夹,包括解决crd的rbac, cert, webhook的文件。暂时不用管他们,这时需要保证你的终端能访问k8s的测试集群,简单就是用kubectl cluster-info看看是否出错,如果不出错,就可以run起来main.go了

kubectl cluster-info
go run main.go

会有点久,不急,一两分钟吧。

然后可以看到终端输出log。

ok, 接下来我们就可以用kubebuilder帮我们创建一个我们想要的crd,我就叫这个crd为Object吧:

kubebuilder create api --group infra --version v1 --kind Object

执行上面的命令之后,kubebuilder就帮我们创建了两个文件api/v1/object_types.go和controllers/object_controller.go, 前者是这个crd需要定义哪些属性,而后者是对crd的reconsile的处理逻辑(也就是增删改crd的逻辑), 我们后面再讲这两个文件。

执行:

make install

把这个报错解决了咱再往下。我一直以为是教程里面的哪一步错了,导致我执行 make install 一直都报错,直到我啥也不动创建完 api 就 make,依旧报错的时候,我就知道事情不简单了。

我反手就打开了 Makefile,一顿操作猛如虎,然后解决了。


回过头我们再看一下api/v1/object_types.go,这里我在spec里面加一个Detail,在status里面加一个Created:

// ObjectSpec defines the desired state of Object
type ObjectSpec struct {
    
    
    // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
    // Important: Run "make" to regenerate code after modifying this file

    // Foo is an example field of Object. Edit Object_types.go to remove/update
    Foo string `json:"foo,omitempty"`
    Detail string `json:"detail,omitempty"`
}

// ObjectStatus defines the observed state of Object
type ObjectStatus struct {
    
    
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run "make" to regenerate code after modifying this file
    Created bool `json:"created,omitempy"`
}

实际上kubebuilder就是帮我们生成Object的spec和status的模板,从注释就也可以看出来spec是我们期望的crd状态,而status就是观测到的状态。可以看到默认定义下面,kubebuilder会为我们生成对应的yaml文件在config/samples/infra_v1_object.yaml:

---
apiVersion: infra.demo.com/v1
kind: Object
metadata:
  name: object-sample
spec:
  # Add fields here
  foo: bar
  detail: "detail for demo"

在controllers/object_controller.go,也就是kubebuilder帮我们生成的Reconcile代码里面,我添加了打印Detail的信息,并且把Created改成true:

//此method在controllers/object_controller.go
func (r *ObjectReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
    
    
    ctx := context.Background()
    _ = r.Log.WithValues("object", req.NamespacedName)
    // your logic here

    // 1. Print Spec.Detail and Status.Created in log
    obj := &infrav1.Object{
    
    }
    if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
    
    
        fmt.Errorf("couldn't find object:%s", req.String())
    } else {
    
    
    //打印Detail和Created
        r.Log.V(1).Info("Successfully get detail", "Detail", obj.Spec.Detail)
        r.Log.V(1).Info("", "Created", obj.Status.Created)
    }
    // 2. Change Created
    if !obj.Status.Created {
    
    
        obj.Status.Created = true
        r.Update(ctx, obj)
    }

    return ctrl.Result{
    
    }, nil
}

接着,再 run 一下那个 main.go 试试,如果日志打印直接截停了,你就知道新的问题出现了,解决掉就好。如果没有截停,那就没事了(我前面之所以反手就打开了 Makefile,就是在日志里面看到的。。。)


现在我们就可以用 config/samples/infra_v1_object.yaml 创建一个 Object:

kubectl create -f config/samples/infra_v1_object.yaml

再看看从k8s里面看到的这个Object的状态:

kubectl get object object-sample -o yaml
apiVersion: infra.demo.com/v1
kind: Object
metadata:
  creationTimestamp: "2022-05-26T11:39:34Z"
  generation: 2
  name: object-sample
  namespace: default
  resourceVersion: "433782"
  selfLink: /apis/infra.demo.com/v1/namespaces/default/objects/object-sample
  uid: 3f4b368d-2988-11ea-a544-080027d6a71e
spec:
  detail: detail for demo
  foo: bar
status:
  Created: true   #此处是我们修改成true的状态

可以看到这个object-sample的status.Created已经被修改为true了


晕吧,我也晕呐,我还去看那本《云原生应用设计与开发》,然后我才意识到,要做这个开发,得对 k8s 的理解再上一层楼才够用。
然后我的预算嘛,这个月先把面铺开,下个月还要重头过一遍实践的。写这一篇,主要也是记录一下我是如何过了 make install 那一关的,不然二十天后实践又要给卡这里了。

最后,附上链接:https://book.kubebuilder.io/
不反感看英文的小伙伴可以去看看,挺好的。

猜你喜欢

转载自blog.csdn.net/qq_43762191/article/details/124983957