万字长文 | 面向k8s编程,如何写一个Operator

云和安全管理服务专家新钛云服刘川川翻译

概述

随着我们对Kubernetes的逐步了解,可能就会发现Kubernetes中内置的对象定义,比如Deployment、StatefulSet、ConfigMap,可能已经不能满足我们的需求。我们希望在Kubernetes定义一些自己的对象,一是可以通过kube-apiserver提供统一的访问入口,二是可以像其他内置对象一样,通过kubectl命令管理这些自定义的对象。

Kubernetes中提供了这种自定义对象的方式,其中之一就是CRD。

CRD介绍

CRD(CustomResourceDefinitions)在刚引入进来的时候,其实是ThirdPartyResources(TPR)的升级版本,而TPR在的版本被剔除了。CRD目前使用非常广泛,各个周边项目都在使用它,比如Ingress、Rancher等。

我们来看一下官方提供的一个例子,通过如下的YAML文件,我们可以创建一个API:

apiVersion:/v1kind:CustomResourceDefinitionmetadata:组名称,用于RESTAPI:/apis/组/版本group:每个版本都可以通过served标志来独立启用或禁止served:true可以是Namespaced或Clusterscope:Namespacednames:名称的单数形式,作为命令行使用时和显示时的别名singular:crontabshortNames允许我们在命令行使用较短的字符串来匹配资源shortNames:-ct

这样我们就可以像创建其他对象一样,通过kubectlcreate命令创建。创建完成以后,一个类型为CronTab的对象就在kube-apiserver中注册好了,我们可以通过如下的REST接口访问,比如查看命名空间ns1下的CronTab对象,可以通过这个URL“/apis//v1/namespaces/ns1/crontabs/”访问。这种接口跟Kubernetes内置的其他对象的接口风格是一模一样的。

声明好了CronTab,我们就来看看如何创建一个CronTab类型的对象。下面依然是来自官方的一个例子:

apiVersion:"/v1"kind:CronTabmetadata:name:new-cron-objectspec:cronSpec:"*****/5"image:awesome-cron-image

通过kubectlcreate创建new-cron-object后,就可以通过kubectlget查看,并使用kubectl管理这个CronTab对象了。例如:

kubectlgetcrontabNAMEAGEnew-cron-object6s

这里的资源名是大小写不敏感的,我们在这里可以使用缩写kubectlgetct,也可以使用kubectlgetcrontabs。同时原生内置的API对象一样,这些CRD不仅可以通过kubectl来创建、查看、修改,删除等操作,还可以给其配置RBAC规则。

我们还可以开发自定义的控制器,来感知和操作这些自定义的API。接下来我们就开始介绍。可以参考定制资源|Kubernetes()这份说明确定是否需要在Kubernetes中定义API,还是让我们的API独立运行。

什么是KubernetesOperator

我们可能对Operator这个名字比较陌生。这个名字最早由CoreOS()在2016年提出来,我们来看看他们给出的定义:

简单概括一下,所谓的KubernetesOperator其实就是借助Kubernetes的控制器模式,配合一些自定义的API,完成对某一类应用的操作,比如资源创建、变更、删除等操作。

这里对Kubernetes的控制器模式做个简要说明。Kubernetes通过声明式API来定义对象,各个控制器负责实时查看对应对象的状态,确保达到定义的期望状态。这就是Kubernetes的控制器模式。


kube-controller-manager就是由这样一组控制器组成的。我们以StatefulSet为例来简单说明下控制器的具体逻辑。

假设我们声明了一个StatefulSet,并将其副本数设置为3。kube-controller-manager中以goroutine方式运行的StatefulSet控制器在观察kube-apiserver的时候,发现了这个新创建的对象,它会先创建一个index为0的Pod,并实时观察这个Pod的状态,待其状态变为Running后,再创建index为1的Pod。后续该控制器会一直观察并维护这些Pod的状态,保证StatefulSet的有效副本数始终为3。

所以我们在声明完成CRD之后,也需要创建一个控制器,即Operator,来完成对应的控制逻辑。在了解了Operator的概念和控制器模式后,我们来看看Operator是如何工作的。

KubernetesOperator是如何工作的

Operator工作的时候采用上述的控制器模式,会持续地观察Kubernetes中的自定义对象,即CR(CustomResource)。我们通过CRD来定义一个对象,CR则是CRD实例化的对象。


Operator会持续跟踪这些CR的变化事件,比如ADD、UPDATE、DELETE,然后采取一系列操作,使其达到期望的状态。上述的流程其实还是有些复杂的,尤其是对运维同学有一定的门槛。好在社区提供了一些脚手架,可以方便我们快速地构建自己的Operator。

构建一个自己的KubernetesOperator

目前社区有一些可以用于创建KubernetesOperator的开源项目,例如:OperatorSDK()、Kubebuilder()、KUDO()。我们这里以OperatorSDK为例,接下来就安装OperatorSDK。

二进制安装OperatorSDK前提条件

curl()

gpg()+

版本信息请参考:kubernetes/client-go:GoclientforKubernetes().()

1、下载二进制文件

设置平台信息:

[root@blog~]exportOS=$(uname|awk'{printtolower($0)}')

下载指定的文件:

[root@blog~]curl-LO${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH}
2、验证已下载的文件(可选)

从导入operator-sdk发行版的GPGkey:

[root@blog~]curl-LO${OPERATOR_SDK_DL_URL}/[root@blog~]gpg-u"OperatorSDK(release)cncf-operator-sdk@"--

我们会看到一些类似下面的一些输出信息:

gpg:assumingsigneddatain''gpg:SignaturemadeFri30Oct202012:15:15PMPDTgpg:usingRSAkeyADE83605E945FA5A1BD8639C59E5B47624962185gpg:Goodsignaturefrom"OperatorSDK(release)cncf-operator-sdk@"[ultimate]

确保checksums匹配:

[root@blog~]chmod+xoperator-sdk_${OS}_${ARCH}sudomvoperator-sdk_${OS}_${ARCH}/usr/local/bin/operator-sdk
源码编译安装OperatorSDK前提条件

git()

+

确保GOPROXY设置为""

[root@blog~]exportGOPROXY=[root@blog~]cdoperator-sdk[root@blogoperator-sdk]operator-sdkversionoperator-sdkversion:"",commit:"560044140c4f3d88677e4ef2872931f5bb97f255",kubernetesversion:"1.21",goversion:"",GOOS:"linux",GOARCH:"amd64"如我们使用的operator-sdk版本为:版本为:1.21[root@blogoperator-sdk]mkdir/root/memcached-operator[root@blogoperator-sdk]exportGO111MODULE=onexportGOPROXY=[root@blogmemcached-operator]tree-L2.├──config│├──default│├──manager│├──manifests│├──prometheus│├──rbac│└──scorecard├──Dockerfile├──├──├──hack│└──├──├──Makefile└──PROJECT8directories,7files

operator-sdkinit生成了一个文件。当我们的工程不在$GOPATH/src下面,则--repo=path选项是必须的,因为脚手架需要一个有效的module路径。

此时,我们可以使用gobuild命令构建:

[root@blogmemcached-operator]lltotal44788drwx------8rootroot100Mar3021:01config-rw-------1rootroot776Mar3020:59Dockerfile-rw-------1rootroot162Mar3021:01:01:59hack-rw-------1rootroot2780Mar3020:59:01Makefile-rwxr-xr-x1rootroot45754092Mar3021:02memcached-operator-rw-------1rootroot235Mar3021:01PROJECT

目录结构中,还有一个PROJECT的文件,我们看看它里面有什么内容。

[root@blogmemcached-operator]operator-sdkcreateapi\--groupcache\--versionv1alpha1\--kindMemcached\--resource\--controller下载了controller-gen文件go:/:/x/:/:/:/:/inconshreveable/:/x/:/:/x/://root/memcached-operator/bin/controller-genobject:headerFile="hack/"paths="./"Next:implementyournewAPIandgeneratethemanifests(,CRs)with:$makemanifests

再次查看PROJECT文件:

[root@blogmemcached-operator]tree-L2.├──api│└──v1alpha1├──bin│└──controller-gen├──config│├──crd│├──default│├──manager│├──manifests│├──prometheus│├──rbac│├──samples│└──scorecard├──controllers│├──memcached_│└──suite_├──Dockerfile├──├──├──hack│└──├──├──Makefile└──PROJECT14directories,10files
理解Kubernetes的APIs

有关KubernetesAPI和group-version-kind模型的深入解读,我们可以查看这些kubebuilderdocs()文档。一般来说,建议让一个控制器负责管理工程的每个API,以遵循controller-runtime()设定的设计目标。

定义API

首先,我们将通过定义“Memcached”类型来表示我们的API,该类型有一个“”字段来设置要部署的memcached实例(CR)的数量,以及一个“”字段来存储CR的Pod名称。

接下来修改api/v1alpha1/memcached_中的Go类型定义,为Memcached自定义资源(CR)定义API,使其具有以下规格和状态:

//MemcachedSpecdefinesthedesiredstateofMemcachedtypeMemcachedSpecstruct{//+kubebuilder:validation:Minimum=0//SizeisthesizeofthememcacheddeploymentSizeint32`json:"size"`}//MemcachedStatusdefinestheobservedstateofMemcachedtypeMemcachedStatusstruct{//NodesarethenamesofthememcachedpodsNodes[]string`json:"nodes"`}


接下来添加+kubebuilder:subresource:statusmarker()以添加statussubresource()到CRD清单,以便控制器可以在不更改CR对象的其余部分的情况下更新CR状态:

//MemcachedistheSchemaforthememcachedsAPI//+kubebuilder:subresource:status//增加此行typeMemcachedstruct{`json:",inline"``json:"metadata,omitempty"`SpecMemcachedSpec`json:"spec,omitempty"`StatusMemcachedStatus`json:"status,omitempty"`}


修改*_文件后,记得要运行以下命令来为该资源类型生成代码:

[root@blogmemcached-operator]makemanifests/root/memcached-operator/bin/controller-genrbac:roleName=manager-rolecrdwebhookpaths="./"output:crd:artifacts:config=config/crd/bases

这个makefile的manifests目标将调用controller-gen在config/crd/bases/_文件中生成CRD清单。

验证OpenAPI

CRD中定义的OpenAPI验证可确保CR基于一组声明性规则进行验证。所有CRD都应该有验证。有关详细信息,请参阅OpenAPI验证()文档。

实现Controller

对于此示例,将生成的控制器文件controllers/memcached_替换为示例memcached_文件。其代码如下:

/*,(the"License");"ASIS"BASIS,WITHOUTWARRANTIESORCONDITIONSOFANYKIND,ationsundertheLicense.*/packagecontrollersimport(appsv1"/api/apps/v1"corev1"/api/core/v1""/apimachinery/pkg/api/errors"metav1"/apimachinery/pkg/apis/meta/v1""/apimachinery/pkg/types""reflect""time""context""/apimachinery/pkg/runtime"ctrl"/controller-runtime""/controller-runtime/pkg/client"ctrllog"/controller-runtime/pkg/log"cachev1alpha1"/example/memcached-operator/api/v1alpha1")//MemcachedReconcilerreconcilesaMemcachedobjecttypeMemcachedReconcilerstruct{*}//+kubebuilder:rbac:groups=,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete//+kubebuilder:rbac:groups=,resources=memcacheds/status,verbs=get;update;patch//+kubebuilder:rbac:groups=,resources=memcacheds/finalizers,verbs=update//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch//Reconcileispartofthemainkubernetesreconciliationloopwhichaimsto//movethecurrentstateoftheclusterclosertothedesiredstate.//TODO(user):ModifytheReconcilefunctiontocomparethestatespecifiedby//theMemcachedobjectagainsttheactualclusterstate,andthen//performoperationstomaketheclusterstatereflectthestatespecifiedby//theuser.////Formoredetails,checkReconcileanditsResulthere://-(r*MemcachedReconciler)Reconcile(,)(,error){log:=(ctx)//FetchtheMemcachedinstancememcached:={}err:=(ctx,,memcached)iferr!=nil{(err){//Requestobjectnotfound,couldhavebeeletedafterreconcilerequest.////Returnanddon'(""){},nil}//(err,"FailedtogetMemcached"){},err}//Checkifthedeploymentalreadyexists,ifnotcreateanewonefound:={}err=(ctx,{Name:,Namespace:},found)iferr!=(err){//Defineanewdeploymentdep:=(memcached)("CreatinganewDeployment","",,"",)err=(ctx,dep)iferr!=nil{(err,"FailedtocreatenewDeployment","",,"",){},err}//{Requeue:true},nil}elseiferr!=nil{(err,"FailedtogetDeployment"){},err}//Ensurethedeploymentsizeisthesameasthespecsize:=*!=size{=sizeerr=(ctx,found)iferr!=nil{(err,"FailedtoupdateDeployment","",,"",){},err}//Asktorequeueafter1minuteinordertogiveenoughtimeforthe//podsbecreatedontheclustersideandtheoperandbeable//{RequeueAfter:},nil}//UpdatetheMemcachedstatuswiththepodnames//Listthepodsforthismemcached'sdeploymentpodList:={}listOpts:=[]{(),(labelsForMemcached()),}iferr=(ctx,podList,listOpts);err!=nil{(err,"Failedtolistpods","",,"",){},err}podNames:=getPodNames()//!(podNames,){=podNameserr:=().Update(ctx,memcached)iferr!=nil{(err,"FailedtoupdateMemcachedstatus"){},err}}{},nil}//deploymentForMemcachedreturnsamemcachedDeploymentobjectfunc(r*MemcachedReconciler)deploymentForMemcached(m*)*{ls:=labelsForMemcached()replicas:=:={ObjectMeta:{Name:,Namespace:,},Spec:{Replicas:replicas,Selector:{MatchLabels:ls,},Template:{ObjectMeta:{Labels:ls,},Spec:{Containers:[]{{Image:"memcached:1.4.36-alpine",Name:"memcached",Command:[]string{"memcached","-m=64","-o","modern","-v"},Ports:[]{{ContainerPort:11211,Name:"memcached",}},}},},},},}//(m,dep,)returndep}//labelsForMemcachedreturnsthelabelsforselectingtheresources//(namestring)map[string]string{returnmap[string]string{"app":"memcached","memcached_cr":name}}//getPodNamesreturnsthepodnamesofthearrayofpodspassedinfuncgetPodNames(pods[])[]string{varpodNames[]stringfor_,pod:=rangepods{podNames=app(podNames,)}returnpodNames}//(r*MemcachedReconciler)SetupWithManager()error{(mgr).For({}).Owns({}).Complete(r)}
Controllerwatch的资源

controllers/memcached_中的SetupWithManager()函数指定了如何构建控制器以监视CR和该控制器拥有和管理的其他资源。

import(appsv1"/api/apps/v1")func(r*MemcachedReconciler)SetupWithManager()error{(mgr).For({}).Owns({}).Complete(r)}

NewControllerManagedBy()提供了一个控制器构建器,允许各种控制器的配置。

For({})将Memcached类型指定为要监视的主要资源。对于每个Memcached类型的Add/Update/Delete事件,reconcileloop将为该Memcached对象发送一个reconcileRequest(命名空间/key名称)。

Owns({})将Deployments类型指定为要watch的辅助资源。对于每个Deployment类型的添加/更新/删除事件,事件处理程序会将每个事件映射到部署所有者的reconcile“请求”。在这种情况下,是为其创建Deployment的Memcached对象。

Controller配置

在初始化控制器时可以进行许多其他有用的配置。有关这些配置的更多详细信息,可以查看上游builder和controller的帮助文档。

通过MaxConcurrentReconciles选项设置控制器的最大并发Reconciles数。默认为1。

func(r*MemcachedReconciler)SetupWithManager()error{
(mgr).
For({}).
Owns({}).
WithOptions({MaxConcurrentReconciles:2}).
Complete(r)
}

使用predicates()过滤监视事件。

选择EventHandler()的类型以更改监视事件将如何转换为reconcile请求以进行reconcile循环。对于比主次资源更复杂的operator关系,可以使用EnqueueRequestsFromMapFunc()处理程序以将监视事件转换为任意一组reconcile请求。

Reconcileloop

reconcile函数负责在系统的实际状态上执行所需的CR状态。每次在监视的CR或资源上发生事件时,它都会运行,并将根据这些状态是否匹配并返回一些值。

这样,每个Controller都有一个Reconciler对象,该对象带有一个Reconcile()方法,用于实现reconcile循环。reconcile循环传递了Request()参数,该参数是用于查找缓存中的主要资源对象Memcached:

import(ctrl"/controller-runtime"cachev1alpha1"/example/memcached-operator/api/v1alpha1")func(r*MemcachedReconciler)Reconcile(,)(,error){//LookuptheMemcachedinstanceforthisreconcilerequestmemcached:={}err:=(ctx,,memcached)}

有关Reconcilers、客户端以及与资源事件交互的指南,可以参考客户端API()文档。以下是Reconciler的一些可能的返回选项:

发生错误时:

{},err

没有错误时:

{Requeue:true},nil

否则,需要停止Reconcile,如下:

{},nil

在X时间之后,再次Reconcile:

{RequeueAfter:(())},nil

想要获取更多详细信息,检查Reconcile及其文档Reconcilegodoc()。

指定权限及生成RBAC清单

controller需要一定的RBAC()权限与其管理的资源进行交互。这些是通过RBAC标记()指定的,如下代码所示:

//+kubebuilder:rbac:groups=,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete//+kubebuilder:rbac:groups=,resources=memcacheds/status,verbs=get;update;patch//+kubebuilder:rbac:groups=,resources=memcacheds/finalizers,verbs=update//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;func(r*MemcachedReconciler)Reconcile(,)(,error){}

TheClusterRolemanifestatconfig/rbac/wingcommand:

[root@blogmemcached-operator]如果不执行这一步,执行下面的命令会报错[root@blogmemcached-operator]BuildthemanagerbinaryFROMgolang:1.16asbuilderWORKDIR/workspacecachedepsbeforebuildingandcopyingsourcesothatwedon'tneedtore-downloadasmuch修改了此行RUNexportGOPROXY=;gomoddownloadBuildRUNCGO_ENABLED=0GOOS=linuxGOARCH=,并新增了FROmalpine:latest注释了此行大概在Makefile文件的第32行,做如下修改,根据实际情况进行修改。大家可以根据实际情况进行修改成自己的IMAGE_TAG_BASE?=lavenliu/memcached-operatorIMG?=controller:latestd'thaveaDockerID,headoverto!Yourpasswordwillbestoredunencryptedin/root/.docker/

登录成功之后,在执行下面的命令:

[root@blogmemcached-operator]makeinstall/root/memcached-operator/bin/controller-genrbac:roleName=manager-rolecrdwebhookpaths="./"output:crd:artifacts:config=config/crd/basesgo::/kustomize/kustomize/v3@/root/memcached-operator/bin/controller-genrbac:roleName=manager-rolecrdwebhookpaths="./"output:crd:artifacts:config=config/crd/bases/root/memcached-operator/bin/controller-genobject:headerFile="hack/"paths="./"gofmt./govet./gorun./:58:25.0541574005942:665],notpriorityandfairness,request:GET:{"addr":":8080"}2022-03-31T17:58:25.605+0800INFOsetupstartingmanager2022-03-31T17:58:25.605+0800INFOstartingmetricsserver{"path":"/metrics"}2022-03-31T17:58:25.605+0800{"reconcilergroup":"","reconcilerkind":"Memcached","source":"kindsource:/,Kind="}2022-03-31T17:58:25.605+0800{"reconcilergroup":"","reconcilerkind":"Memcached","source":"kindsource:/,Kind="}2022-03-31T17:58:25.605+0800{"reconcilergroup":"","reconcilerkind":"Memcached"}2022-03-31T17:58:25.707+0800{"reconcilergroup":"","reconcilerkind":"Memcached","workercount":1}

查看CRD:

[root@blogmemcached-operator]之前的样板文件[root@blogmemcached-operator]TODO(user):Addfieldsherecatconfig/samples/cache_v1alpha1_:/v1alpha1kind:Memcachedmetadata:name:memcached-samplespec:size:3

创建上述CR:

kubectl-nliucc-testgetdeploymentNAMEREADYUP-TO-DATEAVAILABLEAGEhello-spring-svc-deployment1/11179djson-spring-svc-deployment1/11172dmemcached-sample3/33325sworld-spring-svc-deployment1/11178d[root@blogmemcached-operator]kubectl-nliucc-testgetpodsNAMEREADYSTATUSRESTARTSAGEhello-spring-svc-deployment-694b8cb9d4-4sjl51/1Running078djson-spring-svc-deployment-cf88f85c8-rsqdc1/1Running071dmemcached-sample-6c765df685-dtmqg1/1Running051smemcached-sample-6c765df685-nl8ks1/1Running051smemcached-sample-6c765df685-vpmfq1/1Running051sworld-spring-svc-deployment-84b78bc8d4-tvdz81/1Running078d[root@blogmemcached-operator]kubectl-nliucc-testpatchmemcachedmemcached-sample-p'{"spec":{"size":5}}'--type=/memcached-samplepatched[root@blogmemcached-operator]kubectl-nliucc-testgetdeploymentNAMEREADYUP-TO-DATEAVAILABLEAGEhello-spring-svc-deployment1/11179djson-spring-svc-deployment1/11172dmemcached-sample5/5552m27sworld-spring-svc-deployment1/11178d
清理环境

我们可以运行下面的命令,清理已经部署的资源:

[root@blogmemcached-operator]验证deployment是否被删除[root@blogmemcached-operator]验证pod是否被删除[root@blogmemcached-operator]查看make帮助信息[root@blogmemcached-operator]大概在33行IMAGE_TAG_BASE?=修改为一个有效的地址/memcached-operator

接着进行部署:

[root@blogmemcached-operator]echo$?0

验证memcached-operator是否启动成功:

[root@blogmemcached-operator]kubectl-nmemcached-operator-systemgetpoNAMEREADYSTATUSRESTARTSAGEmemcached-operator-controller-manager-7bbc46698f-wsqvp0/2ContainerCreating050s

报错了,主要原因是拉取镜像失败及运行容器时也失败了。查看一下错误原因:

[root@blogmemcached-operator]vimconfig/default/manager_auth_proxy_:template:spec:securityContext:新增此行containers:-name:kube-rbac-proxy镜像拉取不成功,所以注释了此行新增此行

修改完成之后,执行makeundeloy命令:

[root@blogmemcached-operator]makedeploy

最后查看deployment及pod信息:

[root@blogmemcached-operator]kubectl-nmemcached-operator-systemgetpoNAMEREADYSTATUSRESTARTSAGEmemcached-operator-controller-manager-54548dbf4d-drnhp2/2Running04m15s[root@blogmemcached-operator]kubectl-nliucc-testapply-fconfig/samples/cache_v1alpha1_

查看pod信息:

[root@blogmemcached-operator]kubectl-nliucc-testpatchmemcachedmemcached-sample-p'{"spec":{"size":5}}'--type=/memcached-samplepatchedkubectl-nliucc-testgetpoNAMEREADYSTATUSRESTARTSAGEhello-spring-svc-deployment-694b8cb9d4-4sjl51/1Running078djson-spring-svc-deployment-cf88f85c8-rsqdc1/1Running071dmemcached-sample-6c765df685-7xrn21/1Running07m27smemcached-sample-6c765df685-tdjz81/1Running07m27smemcached-sample-6c765df685-xvpqk1/1Running07m27smemcached-sample-6c765df685-b79kc1/1Running03s新起的podworld-spring-svc-deployment-84b78bc8d4-tvdz81/1Running078d

清除演示环境:

[root@blogmemcached-operator]kubectl-nliucc-testgetpoNAMEREADYSTATUSRESTARTSAGEhello-spring-svc-deployment-694b8cb9d4-4sjl51/1Running078djson-spring-svc-deployment-cf88f85c8-rsqdc1/1Running071dworld-spring-svc-deployment-84b78bc8d4-tvdz81/1Running078d
3、使用OLM部署Operator

首先我们需要安装OLM:

[root@blogmemcached-operator]operator-sdkolmstatusI040611:28:17.35987430074:665],notpriorityandfairness,request:GET:[0002]FetchingCRDsforversion""INFO[0002]Fetchingresourcesforresolvedversion""INFO[0007]SuccessfullygotOLMstatusforversion""sterRoleBindingInstalledoperatorhubio-catalogolmCatalogSourceInstalledolm-operatorsolmOperatorGroupInstalledaggregate-olm-viewClusterRoleInstalledcatalog-oleInstalledolmNamespaceInstalledglobal-operatorsoperatorsOperatorGroupInstalledoperatorsNamespaceInstalledpackageserverolmClusterServiceVersionInstalledolm-:controller:operator-lifecycle-managerClusterRoleInstalled

我们看一下中间生成了哪些命名空间及POD:

[root@blogmemcached-operator]kubectl-nolmgetpoNAMEREADYSTATUSRESTARTSAGEcatalog-operator-5c4997c789-tk5cq1/1Running0103molm-operator-6d46969488-rc8zf1/1Running0103moperatorhubio-catalog-nt5vw1/1Running0103mpackageserver-848bdb76dd-6snj41/1Running0103mpackageserver-848bdb76dd-grdx41/1Running0103m

接下来对我们的Operator进行打包,然后构建并推送包镜像。bundle目标在bundle目录包含定义了我们的operator清单和元数据。bundle-build和bundle-push两个目标将会构建和推送由文件定义的包镜像。

[root@blogmemcached-operator]需要填写如下信息memcached-operatorDescriptionfortheoperator(required):需要填写如下信息lavenliuAnyrelevantURLfortheprovidername(optional):Comma-separatedlistofkeywordsforyouroperator(required):需要填写如下信息lcc@163.comcdconfig/manager/root/memcached-operator/bin/kustomizeeditsetimagecontroller=lavenliu/memcached-operator:0.0.1/root/memcached-operator/bin/kustomizebuildconfig/manifests|[0000]Creatingbundle/metadata/[0000][0000]Bundlemetadatageneratedsuceessfullyoperator-sdkbundlevalidate./bundleINFO[0000]Allvalidationtestshavecompletedsuccessfully

我们看看是否有新的文件或目录产生:

[root@blogmemcached-operator]新产生的目录-rw-r--r--1rootroot923Apr320:11/memcached-operator-bundle:/14:FROMscratch---Step2/14:=registry+v1---Runninginacbee848ff30Removingintermediatecontaineracbee848ff30---7840efc1acc7Step3/14:=manifests/---Runningin795bbd68aa0bRemovingintermediatecontainer795bbd68aa0b---58c64b2c5bedStep4/14:=metadata/---Runningin3ba74dd41232Removingintermediatecontainer3ba74dd41232---4921148bcd53Step5/14:=memcached-operator---Runninginc8ae15420ea2Removingintermediatecontainerc8ae15420ea2---0c417435ceffStep6/14:=alpha---Runningina4c7d20e793bRemovingintermediatecontainera4c7d20e793b---b549d7f0aa94Step7/14:=+git---Runningin3dd418069c6bRemovingintermediatecontainer3dd418069c6b---a0ead127d313Step8/14:=metrics+v1---Runningin513a0223cafbRemovingintermediatecontainer513a0223cafb---97c961869eb3Step9/14:_layout=/v3---Runningin24c6fbf30e77Removingintermediatecontainer24c6fbf30e77---e523f8b86a47Step10/14:=scorecard+v1---Runningin795730b93b89Removingintermediatecontainer795730b93b89---5f186fccf6fbStep11/14:=tests/scorecard/---Runningind29664ae092aRemovingintermediatecontainerd29664ae092a---7776ff18f767Step12/14:COPYbundle/manifests/manifests/---cde9d176b798Step13/14:COPYbundle/metadata/metadata/---38d589cdd086Step14/14:COPYbundle/tests/scorecard/tests/scorecard/---976c6344511bSuccessfullybuilt976c6344511bSuccessfullytaggedlavenliu/memcached-operator-bundle:

再运行makebundle-push目标:

[root@blogmemcached-operator]operator-sdkrunbundlelavenliu/memcached-operator-bundle:

查看docs()深入了解operator-sdk的OLM集成。

总结

经过前面几章的“折腾”,我们终于完成了一个Operator的tutorial。虽然是按照官方文档进行一步一步的操作,但是中间过程还是挺曲折的。希望本文可以帮助到大家,对编写Operator起到参考的作用。

附录推荐阅读

Introduction-TheKubebuilderBook()

OperatorSDK()()

《KubernetesOperators》,这本书使用的operator-sdk版本比较旧,但是里面的讲解还是非常不错的

CoreOS关于Operator的介绍

在()上找到现成的、适合你的Operator

版权声明:本站所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请举报,一经查实,本站将立刻删除。

相关推荐