Kubernetes项目都是用Go语言编写的,原生支持Goapi非常方便。本文介绍如何使用kubernetesclient-go练习一个与K8s的简单交互过程。kubernetes的Go客户端项目(client-go)是k8s客户端中最老的一个,有很多特性。Client-go不使用Swagger生成器。它使用来自k8s项目的源代码生成工具。这个工具的目的是生成k8s风格的对象和序列化器。这个项目是一个包的集合,可以满足从REST风格的原语到复杂的客户端的不同编程需求。RESTClient是一个基础包,它使用api-machinery库中的类型作为一组REST原语提供对API的访问。作为RESTClient之上的抽象,_clientset_将是您创建k8s客户端工具的起点。它公开了公共API资源及其相应的序列化。注:discovery、dynamic、scale等包也包含在client-go中。虽然这次没有介绍这些包,但是了解它们的能力还是很重要的。一个简单的k8s客户端工具让我们重温一下我们要构建的工具,来说明go客户端的用法。pvcwatch是一个简单的命令行工具,用于监视集群中声明的PVC容量。当总数达到阈值时,他将采取行动(在本例中为屏幕上的通知)。你可以在github上找到一个完整的例子。这个例子是为了演示k8sgoclient的以下几个方面:-如何连接-资源列表的检索和遍历-对象监控Setupclient-go支持godep和dep作为厂商的管理程序。觉得dep好用所以继续用dep。例如,以下是client-gov6.0和k8sAPIv1.9所需的最低Gopkg.toml。[[constraint]]name="k8s.io/api"version="kubernetes-1.9.0"[[constraint]]name="k8s.io/apimachinery"version="kubernetes-1.9.0"[[constraint]]name="k8s.io/client-go"version="6.0.0"运行depensure以确保其余工作正常。连接到API服务器Go客户端的第一步是建立到API服务器的连接。为此,我们使用实体包中的clientcmd,如以下代码所示:import(..."k8s.io/client-go/tools/clientcmd")funcmain(){kubeconfig:=filepath.Join(.Getenv("HOME"),".kube","config",)config,err:=clientcmd.BuildConfigFromFlags("",kubeconfig)iferr!=nil{log.Fatal(err)}...}_Client-go_通过提供实体功能从不同的上下文中获取您的配置,使这成为一项不平凡的任务。从配置文件如上例所示,您可以从kubeconfig文件开始配置以连接到API服务器。当您的代码在集群外运行时,这是一个理想的解决方案。clientcmd.BuildConfigFromFlags("",configFile)fromthecluster当你的代码运行在这个集群中时,你可以不带任何参数使用上面的函数,这个函数将使用集群信息连接到api服务器。clientcmd.BuildConfigFromFlags("","")或者我们可以使用rest包创建配置,开始使用集群ServiceAccount中的信息,所以会使用默认的ServiceAccount授权信息),如下:import"k8s.io/client-go/rest"...rest.InClusterConfig()创建一个客户端我们需要创建一个序列化的客户端,以便我们获取API对象。kubernetes包中的Clientset类型定义提供了一个序列化的客户端来访问公共API对象,如下:此配置用于初始化客户端集,如下所示:err)}}对于我们的示例,我们使用的是v1API对象。下一步我们将使用clientset通过CoreV1()访问核心api资源,如下:funcmain(){...clientset,err:=kubernetes.NewForConfig(config)iferr!=nil{log.Fatal(err)}api:=clientset.CoreV1()}你可以在这里看到客户端可用。获取集群的PVC列表我们对客户端执行的最基本操作之一是获取存储的API对象列表。在我们的例子中,我们会得到命名空间下的PVC列表,如下:(&ns,"命名空间","","命名空间")flag.StringVar(&label,"l","","Labelselector")flag.StringVar(&field,"f","","Fieldselector")...api:=clientset.CoreV1()//setuplistoptionslistOptions:=metav1.ListOptions{LabelSelector:label,FieldSelector:field,}pvcs,err:=api.PersistentVolumeClaims(ns).List(listOptions)iferr!=nil{log.Fatal(err)}printPVCs(pvcs)...}在上面的代码中,我们使用ListOptions指定标签和字段选择器(和命名空间)来缩小pvc列表的范围。此结果的返回类型为v1.PeristentVolumeClaimList。下面的代码展示了我们如何遍历并打印从api服务器获取的pvc列表。funcprintPVCs(pvcs*v1.PersistentVolumeClaimList){template:="%-32s%-8s%-8s\n"fmt.Printf(template,"NAME","STATUS","CAPACITY")for_,pvc:=rangepvcs。items{quant:=pvc.Spec.Resources.Requests[v1.ResourceStorage]fmt.Printf(template,pvc.Name,string(pvc.Status.Phase),quant.String())}}监控pvck8s的Go集群客户端框架支持在集群中监视指定API对象在其生命周期事件中的能力,包括创建、更新和删除指定对象时触发的CREATED、MODIFIED和DELETED事件。对于我们的命令行工具,我们将要监控已在集群中声明的PVC总数。对于某个命名空间,当PVC的容量达到某个阈值(比如200Gi)时,我们就会采取一定的动作。为简单起见,我们将在屏幕上打印一条通知。但在更复杂的实现中,可以使用相同的方法来触发自动操作。启动监听功能现在让我们通过Watch为PersistentVolumeClaim资源创建一个监听器。侦听器然后通过ResultChan从go通道访问事件通知。funcmain(){...api:=clientset.CoreV1()listOptions:=metav1.ListOptions{LabelSelector:label,FieldSelector:field,}watcher,err:=api.PersistentVolumeClaims(ns).Watch(listOptions)iferr!=nil{log.Fatal(err)}ch:=watcher.ResultChan()...}循环事件接下来我们将处理资源事件。但是在我们处理事件之前,我们先声明两个resource.Quantity类型的变量为maxClaimsQuant和totalClaimQuant,分别表示我们的应用资源阈值(译者注:表示在某个ns下集群中运行的PVC应用的上限)和运行总数。导入(“k8s.io/apimachinery/pkg/api/resource”...)funcmain(){varmaxClaimsstringflag.StringVar(&maxClaims,“max-claims”,“200Gi”,“Maximumtotalclaimstowatch”)vartotalClaimedQuantresource.QuantitymaxClaimedQuant:=资源。MustParse(maxClaims)...ch:=watcher.ResultChan()forevent:=rangech{pvc,ok:=event.Object.(*v1.PersistentVolumeClaim)if!ok{log.Fatal("unexpectedtype")}...}}在上面的for-range循环中,watcher通道用于处理来自服务器的传入通知。每个事件都赋值给变量event,event.Object的类型声明为PersistentVolumeClaim类型,所以我们可以从中提取。处理ADDED事件创建新PVC时,event.Type值设置为watch.Added。然后我们使用以下代码获取新申领的容量(quant)并将其添加到运行总容量(totalClaimedQuant)中。最后,我们检查当前总容量是否大于原来设置的最大值(maxClaimedQuant),如果是,则触发事件。import("k8s.io/apimachinery/pkg/watch"...)funcmain(){...forevent:=rangech{pvc,ok:=event.Object.(*v1.PersistentVolumeClaim)if!ok{log.Fatal("unexpectedtype")}quant:=pvc.Spec.Resources.Requests[v1.ResourceStorage]switchevent.Type{casewatch.Added:totalClaimedQuant.Add(quant)log.Printf("PVC%sadded,claimsize%s\n",pvc.Name,quant.String())iftotalClaimedQuant.Cmp(maxClaimedQuant)==1{log.Printf("\nClaimoveragereached:max%sat%s",maxClaimedQuant.String(),totalClaimedQuant.String())//triggeractionlog.Println("***Takingaction***")}}...}}}DELETED事件代码也会在PVC被删除时做出反应,它执行相反的逻辑,把被删除的请求的容量从运行容量的总值中减去PVC。funcmain(){...forevent:=rangech{...switchevent.Type{casetwatch.Deleted:quant:=pvc.Spec.Resources.Requests[v1.ResourceStorage]totalClaimedQuant.Sub(quant)log.Printf("PVC%sremoved,size%s\n",pvc.Name,quant.String())iftotalClaimedQuant.Cmp(maxClaimedQuant)<=0{log.Printf("Claimusagenormal:max%sat%s",maxClaimedQuant.String(),totalClaimedQuant.String(),)//triggeractionlog.Println("***Takingaction***")}}...}}运行程序当程序在一个正在运行的集群中执行时,PVC会被列在第一个list的。然后开始监听集群中新的PersistentVolumeClaim事件。$>./pvcwatchUsingkubeconfig:/Users/vladimir/.kube/config---PVCs----NAMESTATUSCAPACITYmy-redis-redisBound50Gimy-redis2-redisBound100Gi------------------------------申请的总容量:150Gi--------------------------------PVCWatch(maxclaims200Gi)----2018/02/1321:55:03PVCmy-redis2-redisadded,claimsize100Giclaimsize50Gi2018/02/1321:55:03At75.0%claimcapcity(150Gi/200Gi)让我们部署一个应用到集群,它会申请75Gi容量存储。(例如,让我们通过helm部署一个influxdb实例)。helminstall--namemy-influx\--setpersistence.enabled=true,persistence.size=75Gistable/influxdb正如你在下面看到的,我们的工具立即响应一个新的语句和一个警告,因为当前运行的语句总是量已经超过了我们设定的门槛。---PVCWatch(maxclaims200Gi)----...2018/02/1321:55:03At75.0%claimcapcity(150Gi/200Gi)2018/02/1322:01:29PVCmy-influx-influxdb添加,claimsize75Gi2018/02/1322:01:29Claimoveragereached:max200Giat225Gi2018/02/1322:01:29***Takingaction***2018/02/1322:01:29At112.5%claimcapcity(225Gi/200Gi)相反,当从cluster,该工具将相应地显示提示。...At112.5%claimcapcity(225Gi/200Gi)2018/02/1411:30:36PVCmy-redis2-redisremoved,size100Gi2018/02/1411:30:36Claimusagenormal:max200Giat125Gi2018/02/1411:30:36***采取行动***总结本文是正在进行的系列文章的一部分,该系列文章使用Go语言的官方k8s客户端与API服务器进行交互。和之前一样,这段代码会逐步实现一个命令行工具来监控指定命名空间下PVC的大小。此代码实现了一个简单的侦听器列表来触发从服务器返回的资源事件。
