1. Kubernetes CRD开发

1.1 kubernetes 自定义资源(CRD)

在研究 Service Mesh 的过程中,发现 Istio 很多参数都通过 kubernetes CRD 来管理,例如 VirtualService 和 DestinationRule,这种方式使部署在 k8s 集群上的服务的管理方式更趋向一致。

kubernetes 的资源管理方式和声明式 API 的良好设计使得在这个平台上的功能扩展变得异常容易。例如 CoreOS 推出的 Operator 框架就是一个很好的例子。

这篇文章通过一个简短的示例来演示如何创建自定义资源。

1.1.1 创建 CRD(CustomResourceDefinition)

这里以创建一个简单的弹性伸缩配置的 CRD 为例。将下面的内容保存在 scaling_crd.yaml 文件中。

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:# name must match the spec fields below, and be in the form: <plural>.<group>name: scalings.control.example.com
spec:# group name to use for REST API: /apis/<group>/<version>group: control.example.com# list of versions supported by this CustomResourceDefinitionversions:- name: v1# Each version can be enabled/disabled by Served flag.served: true# One and only one version must be marked as the storage version.storage: true# either Namespaced or Clusterscope: Namespacednames:# plural name to be used in the URL: /apis/<group>/<version>/<plural>plural: scalings# singular name to be used as an alias on the CLI and for displaysingular: scaling# kind is normally the CamelCased singular type. Your resource manifests use this.kind: Scaling# shortNames allow shorter string to match your resource on the CLIshortNames:- sc

通过 kubectl 创建这个 CRD:

kubectl apply -f scaling_crd.yaml

1.1.2 创建自定义资源的对象

我们编写一个 test.yaml 文件来创建一个自定义的 Scaling 对象。

apiVersion: "control.example.io/v1"
kind: Scaling
metadata:name: test
spec:targetDeployment: testminReplicas: 1maxReplicas: 5metricType: CPUstep: 1scaleUp: 80scaleDown: 40

通过 kubectl 创建:

kubectl apply -f test.yaml

提示:

scaling.control.example.io/test created

你可以通过 kubectl 查看已经创建的名为 test 的 Scaling 对象。

kubectl get scalings.control.example.io test -o yaml

会输出类似如下的结果:

apiVersion: control.example.io/v1
kind: Scaling
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"control.example.io/v1","kind":"Scaling","metadata":{"annotations":{},"name":"test","namespace":"default"},"spec":{"maxReplicas":5,"metricType":"CPU","minReplicas":1,"scaleDown":40,"scaleUp":80,"step":1,"targetDeployment":"test"}}creationTimestamp: "2019-01-09T12:22:36Z"generation: 1name: testnamespace: defaultresourceVersion: "1316610"selfLink: /apis/control.example.io/v1/namespaces/default/scalings/testuid: 28717b37-5ac2-11e9-89f8-080027a9fd96
spec:maxReplicas: 5metricType: CPUminReplicas: 1scaleDown: 40scaleUp: 80step: 1targetDeployment: test

我们可以像操作 k8s 内置的 Deployment 资源一样操作我们创建的 Scaling 资源,同样可以对它进行更新和删除的操作。

1.1.3 参数校验

上面的 CRD 配置中我们并没有指定这个资源的 Spec,也就是说用户可以使用任意的 Spec 创建这个 Scaling 资源,这并不符合我们的要求。我们希望在用户创建 Scaling 对象时,可以像 k8s 的原生资源一样进行参数校验,如果出错的情况下,就不会去创建或更新这个对象,而是给用户错误提示。

k8s 目前提供了两种方式来实现参数校验,OpenAPI v3 schemavalidatingadmissionwebhook

这里主要使用比较简单的 OpenAPI v3 schema 来实现。validatingadmissionwebhook 需要用户自己提供一个检查服务,通过创建 ValidatingWebhookConfiguration 让 APIServer 将指定的操作请求转发给这个检查服务,检查服务返回 true 或者 false,决定参数校验是否成功。

我们将之前的 CRD 配置文件 scaling_crd.yaml 做一下修改,增加参数校验的部分:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:name: scalings.control.example.io
spec:group: control.example.ioversions:- name: v1served: truestorage: truescope: Namespacednames:plural: scalingssingular: scalingkind: Scalingvalidation:openAPIV3Schema:properties:spec:required:- targetDeployment- minReplicas- maxReplicas- metricType- step- scaleUp- scaleDownproperties:targetDeployment:type: stringminReplicas:type: integerminimum: 0maxReplicas:type: integerminimum: 0metricType:type: stringenum:- CPU- MEMORY- REQUESTSstep:type: integerminimum: 1scaleUp:type: integerscaleDown:type: integerminimum: 0

可以看到 spec 中增加了 validation 字段,其中定义了对各个参数的检验要求。

  • required 表示数组中的参数必须要设置。
  • type stringtype integer 表示限制参数类型。
  • minimum: 0 表示数字最小值为 0。
  • enum 表示参数只能在指定的值中。

具体支持哪些校验方法可以通过 https://github.com/OAI/OpenAPI-Specification 查看。

更新 CRD 资源:

kubectl apply -f scaling_crd.yaml

再次修改 test.yaml 测试我们的参数校验是否生效,将 targetDeployment: test 这一行删除。

更新 Name 为 test 的 Scaling 对象。

kubectl apply -f test.yaml

可以看到错误提示输出如下:

validation failure list:
spec.targetDeployment in body is required

至此,不符合我们要求的 Scaling 对象将不被允许创建。

1.2 kubernetes 自定义控制器

kubernetes 的 controller-manager 通过 APIServer 实时监控内部资源的变化情况,通过各种操作将系统维持在一个我们预期的状态上。比如当我们将 Deployment 的副本数增加时,controller-manager 会监听到此变化,主动创建新的 Pod。

对于通过 CRD 创建的资源,也可以创建一个自定义的 controller 来管理。

1.2.1 目的

在上文中我们创建了自己的 Scaling 资源,如果我们想要通过监听该资源的变化来实现实时的弹性伸缩,就需要自己写一个控制器,通过 APIserver watch 该资源的变化。

当我们创建了一个 Scaling 对象,自定义控制器都能获得其参数,之后执行相关的检查,根据结果决定是否需要扩容或缩容相关的实例。

1.2.2 实现

client-go 这个 repo 封装了对 k8s 内置资源的一些常用操作,包括了 clients/listers/informer 等对象和函数,可以 通过 Watch 或者 Get List 获取对应的 Object,并且通过 Cache,可以有效避免对 APIServer 频繁请求的压力。

但是对于我们自己创建的 CRD,没有办法直接使用这些代码。

通过 code-generator 这个 repo,我们可以提供自己的 CRD 相关的结构体,轻松的生成 client-go 中类似的代码,方便我们编写自己的控制器。

1.2.3 在自己的项目中使用 code-generator

这里主要参考了 sample-controller 这个项目。

1.2.3.1 创建自定义 CRD 结构体

假设我们有一个 test repo,在根目录创建一个 pkg 目录,用于存放我们自定义资源的 Spec 结构体。

这里我们要知道自己创建的自定义资源的相关内容:

  • API Group: 我们使用的是 control.example.com
  • Version: 我们用的是 v1,但是可以同时存在多个版本。
  • 资源名称: 这里是 Scaling

接着创建如下的目录结构:

mkdir -p pkg/apis/control/v1

pkg/apis/control 目录下创建一个 register.go 文件。内容如下:

package controlconst (GroupName = "control.example.com"
)

创建 pkg/apis/control/v1/types.go 文件,内容如下:

package v1import (metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Objecttype Scaling struct {metav1.TypeMeta   `json:",inline"`metav1.ObjectMeta `json:"metadata,omitempty"`Spec ScalingSpec `json:"spec"`
}type ScalingSpec struct {TargetDeployment string `json:"targetDeployment"`MinReplicas      int    `json:"minReplicas"`MaxReplicas      int    `json:"maxReplicas"`MetricType       string `json:"metricType"`Step             int    `json:"step"`ScaleUp          int    `json:"scaleUp"`ScaleDown        int    `json:"scaleDown"`
}// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Objecttype ScalingList struct {metav1.TypeMeta `json:",inline"`metav1.ListMeta `json:"metadata,omitempty"`Items []Scaling `json:"items"`
}

这个文件中我们定义了 Scaling 这个自定义资源的结构体。

其中,类似 // +<tag_name>[=value] 这样格式的注释,可以控制代码生成器的一些行为。

  • +genclient: 为这个 package 创建 client。
  • +genclient:noStatus: 当创建 client 时,不存储 status。
  • +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object: 为结构体生成 deepcopy 的代码,实现了 runtime.Object 的 Interface。

创建 doc 文件,pkg/apis/control/v1/doc.go:

// +k8s:deepcopy-gen=package
// +groupName=control.example.compackage v1

最后 client 对于自定义资源结构还需要一些接口,例如 AddToSchemeResource,这些函数负责将结构体注册到 schemes 中去。

为此创建 pkg/apis/control/v1/register.go 文件:

package v1import ("test/pkg/apis/control"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/runtime""k8s.io/apimachinery/pkg/runtime/schema"
)var SchemeGroupVersion = schema.GroupVersion{Group:   control.GroupName,Version: "v1",
}func Resource(resource string) schema.GroupResource {return SchemeGroupVersion.WithResource(resource).GroupResource()
}var (// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.SchemeBuilder      runtime.SchemeBuilderlocalSchemeBuilder = &SchemeBuilderAddToScheme        = localSchemeBuilder.AddToScheme
)func init() {// We only register manually written functions here. The registration of the// generated functions takes place in the generated files. The separation// makes the code compile even when the generated files are missing.localSchemeBuilder.Register(addKnownTypes)
}// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Scaling{},&ScalingList{},)metav1.AddToGroupVersion(scheme, SchemeGroupVersion)return nil
}

至此,初期的准备工作已近完成,可以通过代码生成器来自动帮助我们生成相关的 client, informer, lister 的代码。

1.2.3.2 生成代码

通常我们通过创建一个 hack/update-codegen.sh 脚本来固化生成代码的步骤。

$GOPATH/src/k8s.io/code-generator/generate-groups.sh all \
test/pkg/client \
test/pkg/apis \
control:v1

可以看到,执行这个脚本,需要使用 code-generator 中的的脚本,所以需要先通过 go get 将 code-generator 这个 repo 的内容下载到本地,并且编译出相关的二进制文件(client-gen, informer-gen, lister-gen)。

执行完成后,可以看到 pkg 目录下多了一个 client 目录,其中就包含了 informer 和 lister 相关的代码。

并且在 pkg/apis/control/v1 目录下,会多一个 zz_generated.deepcopy.go 文件,用于 deepcopy 相关的处理。

1.2.3.3 创建自定义控制器代码

这里只创建一个 main.go 文件用于简单示例,通过我们刚刚自动生成的代码,每隔一段时间,自动通过 lister 获取所有的 Scaling 对象。

package mainimport ("fmt""log""os""time""k8s.io/apimachinery/pkg/labels""k8s.io/client-go/tools/clientcmd"clientset "test/pkg/client/clientset/versioned"informers "test/pkg/client/informers/externalversions"
)func main() {client, err := newCustomKubeClient()if err != nil {log.Fatalf("new kube client error: %v", err)}factory := informers.NewSharedInformerFactory(client, 30*time.Second)informer := factory.Control().V1().Scalings()lister := informer.Lister()stopCh := make(chan struct{})factory.Start(stopCh)for {ret, err := lister.List(labels.Everything())if err != nil {log.Printf("list error: %v", err)} else {for _, scaling := range ret {log.Println(scaling)}}time.Sleep(5 * time.Second)}
}func newCustomKubeClient() (clientset.Interface, error) {kubeConfigPath := os.Getenv("HOME") + "/.kube/config"config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)if err != nil {return nil, fmt.Errorf("failed to create out-cluster kube cli configuration: %v", err)}cli, err := clientset.NewForConfig(config)if err != nil {return nil, fmt.Errorf("failed to create custom kube client: %v", err)}return cli, nil
}

编译并执行此代码,每隔 5 秒钟,会在标准输出中输出我们创建的所有 Scaling 对象的具体内容。

需要注意的是,这里生成的 kube client 只能用于操作我们自己的 Scaling 对象。如果需要操作 Deployment 这一类的内置的资源,仍然需要使用 client-go 中的代码,因为不同的 clientset.Interface 实现的接口也是不同的。

上述的方法也是最顶层的实现方式,下面介绍两种可以快速搭建CRD开发的工具:一种是kubebuilder,另一种是operader-sdk,该工具目前正在与kubebuilder融合,其中kubebuilder是一个官方提供的快速实现Operator的工具包,可以快速生成k8s的CRD、Controller、Webhook,我们只需要实现业务逻辑。

kubebuilder封装了controller-runtime和controller-tools工具,通过controller-gen来生成代码,提供脚手架工具初始化 CRDs 工程,自动生成 boilerplate 代码和配置;提供代码库封装底层的 K8s client-go;简化了用户创建Operator的步骤:

  1. 创建工作目录,初始化项目
  2. 创建API,填充字段
  3. 定义 CRD
  4. 编写 Controller 逻辑
  5. 验证测试
  6. 发布到集群中

1.3 kubebuilder 开发自定义资源(CRD)

1.3.1 创建脚手架工程

kubebuilder init --domain edas.io1

这一步创建了一个 Go module 工程,引入了必要的依赖,创建了一些模板文件。

1.3.2 创建 API

kubebuilder create api --group apps --version v1alpha1 --kind Application1

这一步创建了对应的 CRD 和 Controller 模板文件,经过 1、2 两步,现有的工程结构如图 2 所示:

1.3.3 定义 CRD

在上图中对应的文件edasapplication_types.go定义 Spec 和 Status。

1.3.4 编写 Controller 逻辑

在上图中对应的文件edasapplication_controller.go实现 Reconcile 逻辑。

1.3.5 测试发布

本地测试完之后使用 Kubebuilder 的 Makefile 构建镜像,部署我们的 CRDs 和 Controller 即可。

1.4 operator-sdk 开发自定义资源(CRD)

该 SDK 提供了一个工作流程,用于使用 Go、 Ansible 或 Helm来开发operators。

下面的工作流用于创建新的 Go operator:

  1. 创建新的 operator project,使用 SDK Command Line Interface(CLI)。
  2. 定义新的resource APIs,通过添加Custom Resource Definitions(CRD)。
  3. 定义 Controllers 观察和协调资源。
  4. 编写协调逻辑,使用 SDK 和 controller-runtime APIs。
  5. 使用 SDK CLI 构建和生成 operator deployment manifests。

下面的工作流用于创建新的Ansible operator:

  1. 创建新的 operator project,使用SDK Command Line Interface(CLI)。
  2. 编写协调逻辑,为自己的对象,使用ansible playbooks 和 roles。
  3. 使用 SDK CLI 构建和生成 operator deployment manifests。
  4. 可选添加额外的 CRD’s,使用 SDK CLI,重复步骤2、3。

下面的工作流用于创建新的Helm operator:

  1. 创建新的 operator project,使用 SDK Command Line Interface(CLI)。
  2. 创建新的 (或添加已有的) Helm chart,用于 operator’s 协调逻辑使用。
  3. 使用SDK CLI 构建和生成operator deployment manifests。
  4. 可选添加额外的CRD’s,使用SDK CLI,重复步骤 2 和 3。

下面就以Go来创建一个operators开发示例

1.4.1 创建脚手架工程

$ operator-sdk new app-operator
$ cd app-operator

1.4.2 创建API

$ operator-sdk add api --api-version=app.example.com/v1alpha1 --kind=AppService

1.4.3 创建控制器

$ operator-sdk add controller --api-version=app.example.com/v1alpha1 --kind=AppService

1.4.4 编译并PUSH镜像

$ operator-sdk build quay.io/example/app-operator
$ docker push quay.io/example/app-operator

1.4.5 测试发布

$ kubectl create -f deploy/

1.5 总结

通过上述介绍来看Kubernetes 中CRD 的开发方式有多种,其中第一种不借用工具的开发方式其实使用的方法是调用client-go 和 code-generate两个工具库中的方法实现CRD资源的管理,涉及的知识点也相对底层,如果阅读了k8s kube-apiserver源码的人更加容易理解这种开发方式;通过kubebuilder和operator-sdk这两种工具的开发方式其实都是将client-go、controller-runtime和controller-tools代码进行了再封装,封装后的库为controller-gen,其目的是简化用户在不理解kube-apiserver等实现的基础上开发CRD的流程。

Kubernetes CRD开发汇总相关推荐

  1. Kubernetes CRD开发模式及源码实现深入剖析-Kubernetes商业环境实战

    专注于大数据及容器云核心技术解密,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客.如有任何学术交流,可随时联系.留言请关注<数据云技术社区>公众号. 1 CRD资源扩展 CRD ...

  2. Kubernetes CRD开发工具Operator-SDK简介

    原文连接:https://blog.csdn.net/weixin_33918114/article/details/92211707 概览 原文来自:https://github.com/opera ...

  3. 深入了解Kubernetes CRD开发工具kubebuilder

    原文连接:https://blog.csdn.net/u012986012/article/details/120271091 普通开发流程 如果不借助任何Operator脚手架,我们是如何实现Ope ...

  4. Kubernetes CRD开发实践

    背景 Kubernetes的最大亮点之一必定是它的声明式API设计,所谓的声明式就是告诉Kubernetes你要什么,而不是告诉它怎么做命令.我们日常使用Kubernetes做编排工作的时候,经常会接 ...

  5. 【云原生】Kubernetes CRD 详解(Custom Resource Definition)

    文章目录 一.概述 二.定制资源 1)定制资源 和 定制控制器 2)定制控制器 3)Operator 介绍 1.Operator Framework 2.Operator 安装 3.安装 Operat ...

  6. Kubernetes CRD (CustomResourceDefinition) 自定义资源类型

    目录 1.CRD (CustomResourceDefinition) 介绍 1.1 client-go 组件 1.2 Custom Controller 组件 2.环境.软件准备 3.Kuberne ...

  7. 资源放送丨《 Kubernetes Operator 开发范式》PPT视频

    回顾:之前,墨天轮邀请到PingCAP工程师 吴叶磊 分享了直播< Kubernetes Operator 开发范式>,在这里我们共享一下PPT和视频,供大家参考学习. Kubernete ...

  8. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总

    iOS开发系列--通讯录.蓝牙.内购.GameCenter.iCloud.Passbook系统服务开发汇总 --系统应用与系统服务 iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如 ...

  9. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总,icloudpassbook

    iOS开发系列--通讯录.蓝牙.内购.GameCenter.iCloud.Passbook系统服务开发汇总,icloudpassbook --系统应用与系统服务 iOS开发过程中有时候难免会使用iOS ...

最新文章

  1. wait跟sleep的区别
  2. kaldi 源码分析(十) - gmm-init-mono.c分析
  3. ASP.NET Core2基于RabbitMQ对Web前端实现推送功能
  4. ECCV 2020 | 微软亚洲研究院精选论文摘录
  5. java启动参数_Java启动参数的思考
  6. oracle内存参数越大越好吗,什么是Oracle内存参数调优技术?
  7. anndroid 之 Intent(意图)使用示例
  8. 不用wp-pagenav,wordpress自带分页代码调用
  9. java持久层用文件_JAVA中用三种方法将字符串持久化到文件中
  10. VS2013 community卸载后不能重装的问题
  11. 【NOIP2017】【Luogu3951】小凯的疑惑
  12. [转载]CMMI之功能点估算法:EI、EQ和EO
  13. Unity 内置渲染管线、SRP、URP、HDRP区别
  14. 【win10】设置电脑固定IP,解除固定IP
  15. LINUX gdk/X11正确获取DPI/Resolution的函数
  16. 复习jquery菜鸟教程
  17. 九宫格动态密码--快速入门
  18. Swift语言难度大吗?适不适合零基础学习?
  19. 姓名转拼音的几种格式
  20. 2021-04-06-MSF之永恒之蓝

热门文章

  1. oracle11gr2 active data guard,Oracle11gR2 Aactive DataGuard(手动)装配部署及维护文档(三)之升级及rman...
  2. 数据中心基础设施运维是什么?
  3. 谷歌开始用AI技术帮助数据中心散热节省成本
  4. 虚拟机备份oracle异常,客户端连接虚拟机Oracle服务器异常
  5. AI:人工智能的多模态融合模型的简介、发展以及未来趋势
  6. keras-yolo3:python库之keras-yolo3的简介、安装、使用方法详细攻略
  7. 成功解决Redirection is not supported
  8. ML之NBLoR:利用NB(朴素贝叶斯)、LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析—五分类预测
  9. HighNewTech:70后、80后、90后、95后职场人大数据调查(有趣的五个结论)——源于猎聘网
  10. HighNewTech之QAB:重新温读张首晟教授2018年8月演讲PPT《量子计算, 人工智能与区块链》