资讯专栏INFORMATION COLUMN

kubebuilder扩展k8s

社区管理员 / 1061人阅读

kubebuilder是个专门用于开发k8s的框架

k8s有很多资源如deployment,cronjob等资源,这些资源的行为则由位于controller-manager中的各个资源控制器来实现逻辑,

安装

https://github.com/kubernetes-sigs/kubebuilder/releases下载合适的二进制文件并放入path中

术语

  • GV: Api Group和Version

    • API Group 是相关API功能的集合,

    • 每个 Group 拥有一或多个Versions

  • GVK: Group Version Kind

    • 每个GV都包含很多个api 类型,称之为Kinds,不同Version同一个Kinds可能不同

  • GVR: Group Version Rsource

    • Resource 是 Kind 的对象标识,一般来Kind和Resource 是1:1 的,但是有时候存在 1:n 的关系,不过对于Operator来说都是 1:1 的关系

</>复制代码

  1. apiVersion: apps/v1 # 这个是 GV,G 是 apps,V 是 v1kind: Deployment    # 这个就是 Kindsepc:               # 加上下放的 spec 就是 Resource了

根据GVK K8s就能找到你到底要创建什么类型的资源,根据你定义的Spec创建好资源之后就成为了Resource,也就是GVR。GVK/GVR就是K8s资源的坐标,是我们创建/删除/修改/读取资源的基础

类似这样的关系/group/version/kind

项目初始化

完整代码:https://github.com/NatureLR/code-example/tree/master/operator

需求背景

我们在部署服务的时候经常需要同时部署deployment和svc这样很复杂,于是自定义一个资源叫appx,让appx来创建svc和deployment

初始化文件夹

在项目文件夹下执行

</>复制代码

  1. kubebuilder init --repo github.com/naturelr/code-example/operator --domain naturelr.cc --skip-go-version-check

这个时候目录下会产生一些文件

</>复制代码

  1. ├── Dockerfile # 编译docker镜像
  2. ├── Makefile # 编译部署相关的脚本,常用功能都在里面
  3. ├── PROJECT # 项目说明
  4. ├── config # 这个目录都是一些需要安装到集群的文件
  5. │   ├── default # 默认配置
  6. │   ├── manager # crd文件
  7. │   ├── prometheus # 监控相关的如ServiceMonitor
  8. │   └── rbac # rbac文件
  9. ├── go.mod
  10. ├── go.sum
  11. ├── hack
  12. │   └── boilerplate.go.txt
  13. └── main.go
  14. 6 directories, 24 files

创建api模板

执行下面的命令,创建api,期间会问你是不是需要创建Resource和Controller,这里我们都选y

</>复制代码

  1. kubebuilder create api --group appx --version v1 --kind Appx

完成之后多了一些目录

</>复制代码

  1. .
  2. ├── Dockerfile
  3. ├── Makefile
  4. ├── PROJECT
  5. ├── api
  6. │   └── v1 # 我们自定义的api
  7. ├── bin
  8. │   └── controller-gen # 生成文件的程序
  9. ├── config
  10. ├── controllers
  11. │   ├── appx_controller.go # 控制逻辑写在这
  12. │   └── suite_test.go # 测试用例
  13. ├── go.mod
  14. ├── go.sum
  15. ├── hack
  16. │   └── boilerplate.go.txt
  17. └── main.go
  18. 12 directories, 10 files

实现

定义字段

api/v1/application_types.go中的AppxSpec写上需要的字段

</>复制代码

  1. type AppxSpec struct {
  2.  // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
  3.  // Important: Run "make" to regenerate code after modifying this file
  4.  // Foo is an example field of Appx. Edit appx_types.go to remove/update
  5.  Image string `json:"image,omitempty"`
  6.  Port  int    `json:"port,omitempty"`}

然后执行make manifests generate命令生成crd文件

生成的crd文件在config/crd/bases/

实现控制器

有crd只能在k8s中定义cr但是k8s并不知道如何处理这些cr,所以我们要实现控制器来处理这些逻辑

我们需要实现的控制器逻辑在controllers/application_controller.go中的Reconcile函数中

逻辑改完之后就需要上测试了,执行make install安装crd到集群,注意他会安装到~/.kube/config这个配置文件中的集群

然后执行make run运行控制器,他会打印很多日志

  • 获取cd,拿到cr中定义的镜像和端口号

</>复制代码

  1. appx := &appxv1.Appx{}if err := r.Get(ctx, req.NamespacedName, appx); err != nil {
  2.  return ctrl.Result{}, err}
  • 拿到信息之后需要创建对应的deployment对象和service对象,需要特别注意的是要管理创建的资源,不然删除的不会删除创建的子资源

</>复制代码

  1. svc := &apiv1.Service{}if err := r.Get(ctx, req.NamespacedName, svc); err != nil {
  2.   if client.IgnoreNotFound(err) != nil { 
  3.     return ctrl.Result{}, err// 如果有错误且不是没找到的话就直接返回错误
  4.   }
  5.   // 没找到就创建资源
  6.   if svc.Name == "" {
  7.     l.Info("创建service:", "名字", appx.Name)
  8.     svc = &apiv1.Service{
  9.       ObjectMetametav1.ObjectMeta{
  10.         Name:      req.Name,
  11.         Namespacereq.Namespace,
  12.       },
  13.         Specapiv1.ServiceSpec{
  14.         Selector: map[string]string{"app": req.Name},
  15.         Ports: []apiv1.ServicePort{{
  16.           Port:       int32(appx.Spec.Port),
  17.           TargetPortintstr.FromInt(appx.Spec.Port),
  18.         },
  19.         },
  20.       },
  21.     }
  22.     // 关联 appx和deployment
  23.     if err := controllerutil.SetOwnerReference(appx, svc, r.Scheme); err != nil {
  24.        return ctrl.Result{}, err    }
  25.     if err := r.Create(ctx, svc); err != nil {
  26.        return ctrl.Result{}, err    }
  27.     l.Info("创建service成功")
  28.   }}
  • 如果已经有此资源,那么可能就需要更新资源了

</>复制代码

  1. // svcsvc.Spec.Ports = []apiv1.ServicePort{{Port: int32(appx.Spec.Port)}}l.Info("更新service""port", appx.Spec.Image)if err := r.Update(ctx, svc); err != nil {
  2.    return ctrl.Result{}, err}l.Info("service更新完成")

到此一个简单的crd的控制逻辑就完成了

status

上面创建的cr当查看的时候并不会显示status

  • api/v1/appx_types.go中找到AppxStatus,添加上合适的字段

</>复制代码

  1. // AppxStatus defines the observed state of Appxtype AppxStatus struct {
  2.   // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
  3.   // Important: Run "make" to regenerate code after modifying this file
  4.   // 必须要有json tag
  5.   Workload int32  `json:"workload"`
  6.   Svc      string `json:"svc"`}
  • controllers/application_controller.go中更新status字段

</>复制代码

  1. appx.Status.Workload = *deploy.Spec.Replicas
  2. appx.Status.Svc = fmt.Sprintf("%d", svc.Spec.Ports[0].Port)r.Status().Update(ctx, appx)

</>复制代码

  1. // 注意type要对应上字段!!!
  2. //+kubebuilder:printcolumn:JSONPath=".status.workload",name=Workload,type=integer
  3. //+kubebuilder:printcolumn:JSONPath=".status.svc",name=Svc,type=string
  • 同样需要重新生成crd并且要安装

event事件

evnet事件,有的时候告诉我们一些重要的信息

  • controllers/application_controller.go中增加字段

</>复制代码

  1. // AppxReconciler reconciles a Appx objecttype AppxReconciler struct {
  2.   client.Client
  3.   Scheme   *runtime.Scheme
  4.   Recorder record.EventRecorder//增加事件结构体}
  • 调用

</>复制代码

  1. r.Recorder.Event(appxapiv1.EventTypeNormal, "找到cr", appx.Name)
  • main.go中加上Recorder的初始化逻辑

</>复制代码

  1. if err = (&controllers.AppxReconciler{
  2.   Client:   mgr.GetClient(),
  3.   Scheme:   mgr.GetScheme(),
  4.   Recorder: mgr.GetEventRecorderFor("Appx"), //+}).SetupWithManager(mgr); err != nil {
  5.   setupLog.Error(err, "unable to create controller""controller""Appx")
  6.   os.Exit(1)}

</>复制代码

  1. $ kubectl get event
  2. LAST SEEN   TYPE     REASON   OBJECT     MESSAGE
  3. 2m55s       Normal   找到cr     appx       
  4. 4s          Normal   找到cr     appx/foo   foo

常用命令

</>复制代码

  1. # 初始化kubebuilder init --repo github.com/naturelr/code-example/operator --domain naturelr.cc --skip-go-version-check# 创建 apikubebuilder create api --group appx --version v1 --kind Appx# 创建webhookkubebuilder create webhook --group nodes --version v1 --kind Appx --defaulting --programmatic-validation# 生成文件make manifests generate# 安装crd等文件make install# 本地调试运行make run

参考资料


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/127897.html

相关文章

  • k8s与HPA--通过 Prometheus adaptor 来自定义监控指标

    摘要:与通过来自定义监控指标自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。适配器删除后缀并将度量标记为计数器度量标准。负载测试完成后,会将部署缩到其初始副本您可能已经注意到自动缩放器不会立即对使用峰值做出反应。 k8s与HPA--通过 Prometheus adaptor 来自定义监控指标 自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。 Kubernetes中的自...

    孙吉亮 评论0 收藏0
  • k8s与HPA--通过 Prometheus adaptor 来自定义监控指标

    摘要:与通过来自定义监控指标自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。适配器删除后缀并将度量标记为计数器度量标准。负载测试完成后,会将部署缩到其初始副本您可能已经注意到自动缩放器不会立即对使用峰值做出反应。 k8s与HPA--通过 Prometheus adaptor 来自定义监控指标 自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。 Kubernetes中的自...

    HollisChuang 评论0 收藏0
  • k8s与HPA--通过 Prometheus adaptor 来自定义监控指标

    摘要:与通过来自定义监控指标自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。适配器删除后缀并将度量标记为计数器度量标准。负载测试完成后,会将部署缩到其初始副本您可能已经注意到自动缩放器不会立即对使用峰值做出反应。 k8s与HPA--通过 Prometheus adaptor 来自定义监控指标 自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。 Kubernetes中的自...

    ityouknow 评论0 收藏0
  • 坦率的讲,企业容器云选K8S就对了!

    摘要:帮你揭开挡在你与容器云之间的那层神秘面纱,看看你的企业究竟适不适合选用基于的容器云管理平台。那么,选择什么样的容器云平台就已经是箭在弦上的大事了。 本文简单粗暴,直戳泪点,ho,不,是直戳痛点。帮你揭开挡在你与容器云之间的那层神秘面纱,看看你的企业究竟适不适合选用基于K8S的容器云管理平台。 企业对容器云平台的需求现状是什么? 众所周知,Docker很火,一大批互联网公司早已领先一步,...

    SKYZACK 评论0 收藏0
  • k8s扩展资源设计和device-plugin

    摘要:如果上的资源耗尽,这类将无法成功调度。将这个资源及其对应的设备个数记录到更新到。 extended-resources extended-resources在k8s1.9中是一个stable的特性。可以用一句话来概括这个特性: 通过向apiserver发送一个patch node 的请求,为这个node增加一个自定义的资源类型,用于以该资源的配额统计和相应的QoS的配置。 patch ...

    shiweifu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<