如何使用Go構(gòu)建Kubernetes應(yīng)用

這篇文章主要介紹“如何使用Go構(gòu)建Kubernetes應(yīng)用”,在日常操作中,相信很多人在如何使用Go構(gòu)建Kubernetes應(yīng)用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何使用Go構(gòu)建Kubernetes應(yīng)用”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

創(chuàng)新互聯(lián)公司 - 達(dá)州主機(jī)托管,四川服務(wù)器租用,成都服務(wù)器租用,四川網(wǎng)通托管,綿陽服務(wù)器托管,德陽服務(wù)器托管,遂寧服務(wù)器托管,綿陽服務(wù)器托管,四川云主機(jī),成都云主機(jī),西南云主機(jī),達(dá)州主機(jī)托管,西南服務(wù)器托管,四川/成都大帶寬,大帶寬服務(wù)器,四川老牌IDC服務(wù)商

Kubernetes項(xiàng)目使用Go語言編寫,對Go api原生支持非常便捷。本篇文章介紹了如何使用kubernetes client-go實(shí)踐一個(gè)簡單的與K8s交互過程。

kubernetes 的Go Client項(xiàng)目(client-go)

go client是k8s client中最古老的一個(gè),具有很多特性。Client-go 沒有使用Swagger生成器,它使用的是源于k8s項(xiàng)目中的源代碼生成工具,這個(gè)工具的目的是要生成k8s風(fēng)格的對象和序列化程序。

該項(xiàng)目是一組包的集合,該包能夠滿足從REST風(fēng)格的原語到復(fù)雜client的不同的編程需求。

如何使用Go構(gòu)建Kubernetes應(yīng)用

RESTClient是一個(gè)基礎(chǔ)包,它使用api-machinery庫中的類型作為一組REST原語提供對API的訪問。作為對RESTClient之上的抽象,_clientset_將是你創(chuàng)建k8s client工具的起點(diǎn)。它暴露了公開化的API資源及其對應(yīng)的序列化。

注意:在 client-go中還包含了如discovery, dynamic, 和 scale這樣的包,雖然本次不介紹這些包,但是了解它們的能力還是很重要的。

一個(gè)簡單的k8s client 工具

讓我們再次回顧我們將要構(gòu)建的工具,來說明go client的用法。pvcwatch是一個(gè)簡單的命令行工具,它可以監(jiān)聽集群中聲明的PVC容量。當(dāng)總數(shù)到達(dá)一個(gè)閾值的時(shí)候,他會(huì)采取一個(gè)action(在這個(gè)例子中是在屏幕上通知顯示)

如何使用Go構(gòu)建Kubernetes應(yīng)用

你能在github上找到完整的例子

這個(gè)例子是為了展示k8s的go client的以下幾個(gè)方面:- 如何去連接 - 資源列表的檢索和遍歷 - 對象監(jiān)聽

Setup

client-go支持Godep和dep作為vendor的管理程序,我覺得dep便于使用所以繼續(xù)使用dep。例如,以下是client-go v6.0和k8s API v1.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"

運(yùn)行dep ensure確保剩下的工作。

連接 API Server

我們Go client的第一步就是建立一個(gè)與API Server的連接。為了做到這一點(diǎn),我們要使用實(shí)體包中的clientcmd,如下代碼所示:

import (  ...      "k8s.io/client-go/tools/clientcmd"  )  func main() {      kubeconfig := filepath.Join(           os.Getenv("HOME"), ".kube", "config",      )      config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)      if err != nil {          log.Fatal(err)      }  ...  }

_Client-go_通過提供實(shí)體功能來從不同的上下文中獲取你的配置,從而使之成為一個(gè)不重要的任務(wù)。

從config文件

正如上面的例子所做的那樣,你能從kubeconfig文件啟動(dòng)配置來連接API server。當(dāng)你的代碼運(yùn)行在集群之外的時(shí)候這是一個(gè)理想的方案。clientcmd.BuildConfigFromFlags("", configFile)

從集群

當(dāng)你的代碼運(yùn)行在這個(gè)集群中的時(shí)候,你可以用上面的函數(shù)并且不使用任何參數(shù),這個(gè)函數(shù)就會(huì)通過集群的信息去連接api server。

clientcmd.BuildConfigFromFlags("", "")

或者我們可以通過rest包來創(chuàng)建一個(gè)使用集群中的信息去配置啟動(dòng)的(譯者注:k8s里所有的Pod都會(huì)以Volume的方式自動(dòng)掛載k8s里面默認(rèn)的ServiceAccount,所以會(huì)用默認(rèn)的ServiceAccount的授權(quán)信息),如下:

import "k8s.io/client-go/rest"  ...  rest.InClusterConfig()

創(chuàng)建一個(gè)clientset

我們需要?jiǎng)?chuàng)建一個(gè)序列化的client為了讓我們獲取API對象。在kubernetes包中的Clientset類型定義,提供了去訪問公開的API對象的序列化client,如下:

type Clientset struct {      *authenticationv1beta1.AuthenticationV1beta1Client      *authorizationv1.AuthorizationV1Client  ...      *corev1.CoreV1Client  }

一旦我們有正確的配置連接,我們就能使用這個(gè)配置去初始化一個(gè)clientset,如下:

func main() {      config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)      ...      clientset, err := kubernetes.NewForConfig(config)      if err != nil {          log.Fatal(err)      }  }

對于我們的例子,我們使用的是v1的API對象。下一步,我們要使用clientset通過CoreV1()去訪問核心api資源,如下:

func main() {      ...      clientset, err := kubernetes.NewForConfig(config)      if err != nil {          log.Fatal(err)      }      api := clientset.CoreV1()  }

你能在這里看到可以獲得clientsets。

獲取集群的PVC列表

我們對clientset執(zhí)行的最基本操作之一獲取存儲(chǔ)的API對象的列表。在我們的例子中,我們將要拿到一個(gè)namespace下面的pvc列表,如下:

import (  ...      metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"  )  func main() {      var ns, label, field string      flag.StringVar(&ns, "namespace", "", "namespace")      flag.StringVar(&label, "l", "", "Label selector")      flag.StringVar(&field, "f", "", "Field selector")  ...      api := clientset.CoreV1()      // setup list options      listOptions := metav1.ListOptions{          LabelSelector: label,           FieldSelector: field,      }      pvcs, err := api.PersistentVolumeClaims(ns).List(listOptions)      if err != nil {          log.Fatal(err)      }      printPVCs(pvcs)  ...  }

在上面的代碼中,我們使用ListOptions指定 label 和 field selectors (還有namespace)來縮小pvc列表的范圍,這個(gè)結(jié)果的返回類型是v1.PeristentVolumeClaimList。下面的這個(gè)代碼展示了我們?nèi)绾稳ケ闅v和打印從api server中獲取的pvc列表。

func printPVCs(pvcs *v1.PersistentVolumeClaimList) {      template := "%-32s%-8s%-8s\n"      fmt.Printf(template, "NAME", "STATUS", "CAPACITY")      for _, pvc := range pvcs.Items {          quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]          fmt.Printf(              template,               pvc.Name,               string(pvc.Status.Phase),               quant.String())      }  }

監(jiān)聽集群中pvc

k8s的Go client框架支持為指定的API對象在其生命周期事件中監(jiān)聽集群的能力,包括創(chuàng)建,更新,刪除一個(gè)指定對象時(shí)候觸發(fā)的CREATED,MODIFIED,DELETED事件。對于我們的命令行工具,我們將要監(jiān)聽在集群中已經(jīng)聲明的PVC的總量。

對于某一個(gè)namespace,當(dāng)pvc的容量到達(dá)了某一個(gè)閾值(比如說200Gi),我們將會(huì)采取某個(gè)動(dòng)作。為了簡單起見,我們將要在屏幕上打印個(gè)通知。但是在更復(fù)雜的實(shí)現(xiàn)中,可以使用相同的辦法觸發(fā)一個(gè)自動(dòng)操作。

啟動(dòng)監(jiān)聽功能

現(xiàn)在讓我們?yōu)镻ersistentVolumeClaim這個(gè)資源通過Watch去創(chuàng)建一個(gè)監(jiān)聽器。然后這個(gè)監(jiān)聽器通過ResultChan從go的channel中訪問事件通知。

func main() {  ...      api := clientset.CoreV1()      listOptions := metav1.ListOptions{          LabelSelector: label,           FieldSelector: field,      }      watcher, err :=api.PersistentVolumeClaims(ns).        Watch(listOptions)      if err != nil {        log.Fatal(err)      }      ch := watcher.ResultChan()  ...  }

循環(huán)事件

接下來我們將要處理資源事件。但是在我們處理事件之前,我們先聲明resource.Quantity類型的的兩個(gè)變量為maxClaimsQuant和totalClaimQuant來分別表示我們的申請資源閾值(譯者注:代表某個(gè)ns下集群中運(yùn)行的PVC申請的上限)和運(yùn)行總數(shù)。

import(      "k8s.io/apimachinery/pkg/api/resource"      ...  )  func main() {      var maxClaims string      flag.StringVar(&maxClaims, "max-claims", "200Gi",           "Maximum total claims to watch")      var totalClaimedQuant resource.Quantity      maxClaimedQuant := resource.MustParse(maxClaims)  ...      ch := watcher.ResultChan()      for event := range ch {          pvc, ok := event.Object.(*v1.PersistentVolumeClaim)          if !ok {              log.Fatal("unexpected type")          }          ...      }  }

在上面的for-range循環(huán)中,watcher的channel用于處理來自服務(wù)器傳入的通知。每個(gè)事件賦值給變量event,并且event.Object的類型被聲明為PersistentVolumeClaim類型,所以我們能從中提取出來。

處理ADDED事件

當(dāng)一個(gè)新的PVC創(chuàng)建的時(shí)候,event.Type的值被設(shè)置為watch.Added。然后我們用下面的代碼去獲取新增的聲明的容量(quant),將其添加到正在運(yùn)行的總?cè)萘恐校╰otalClaimedQuant)。最后我們?nèi)z查是否當(dāng)前的容量總值大于當(dāng)初設(shè)定的最大值(maxClaimedQuant),如果大于的話我們就觸發(fā)一個(gè)事件。

import(      "k8s.io/apimachinery/pkg/watch"      ...  )  func main() {  ...      for event := range ch {          pvc, ok := event.Object.(*v1.PersistentVolumeClaim)          if !ok {              log.Fatal("unexpected type")          }          quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]          switch event.Type {              case watch.Added:                  totalClaimedQuant.Add(quant)                  log.Printf("PVC %s added, claim size %s\n",                      pvc.Name, quant.String())                  if totalClaimedQuant.Cmp(maxClaimedQuant) == 1 {                      log.Printf(                          "\nClaim overage reached: max %s at %s",                          maxClaimedQuant.String(),                          totalClaimedQuant.String())                      // trigger action                      log.Println("*** Taking action ***")                  }              }          ...          }      }  }

處理DELETED事件

代碼也會(huì)在PVC被刪除的時(shí)候做出反應(yīng),它執(zhí)行相反的邏輯以及把被刪除的這個(gè)PVC申請的容量在正在運(yùn)行的容量的總值里面減去。

func main() {  ...      for event := range ch {          ...          switch event.Type {          case watch.Deleted:              quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]              totalClaimedQuant.Sub(quant)              log.Printf("PVC %s removed, size %s\n",                  pvc.Name, quant.String())              if totalClaimedQuant.Cmp(maxClaimedQuant) <= 0 {                 log.Printf("Claim usage normal: max %s at %s",                      maxClaimedQuant.String(),                      totalClaimedQuant.String(),                  )                  // trigger action                  log.Println("*** Taking action ***")              }          }          ...      }  }

運(yùn)行程序

當(dāng)程序在一個(gè)運(yùn)行中的集群被執(zhí)行的時(shí)候,首先會(huì)列出PVC的列表。然后開始監(jiān)聽集群中新的PersistentVolumeClaim事件。

$> ./pvcwatch  Using kubeconfig:  /Users/vladimir/.kube/config  --- PVCs ----  NAME                            STATUS  CAPACITY  my-redis-redis                  Bound   50Gi  my-redis2-redis                 Bound   100Gi  -----------------------------  Total capacity claimed: 150Gi  -----------------------------  --- PVC Watch (max claims 200Gi) ----  2018/02/13 21:55:03 PVC my-redis2-redis added, claim size 100Gi  2018/02/13 21:55:03  At 50.0% claim capcity (100Gi/200Gi)  2018/02/13 21:55:03 PVC my-redis-redis added, claim size 50Gi  2018/02/13 21:55:03  At 75.0% claim capcity (150Gi/200Gi)

下面讓我們部署一個(gè)應(yīng)用到集群中,這個(gè)應(yīng)用會(huì)申請75Gi容量的存儲(chǔ)。(例如,讓我們通過helm去部署一個(gè)實(shí)例influxdb)。

helm install --name my-influx \  --set persistence.enabled=true,persistence.size=75Gi stable/influxdb

正如下面你看到的,我們的工具立刻反應(yīng)出來有個(gè)新的聲明以及一個(gè)警告因?yàn)楫?dāng)前的運(yùn)行的聲明總量已經(jīng)大于我們設(shè)定的閾值。

--- PVC Watch (max claims 200Gi) ----  ...  2018/02/13 21:55:03  At 75.0% claim capcity (150Gi/200Gi)  2018/02/13 22:01:29 PVC my-influx-influxdb added, claim size 75Gi  2018/02/13 22:01:29  Claim overage reached: max 200Gi at 225Gi  2018/02/13 22:01:29 *** Taking action ***  2018/02/13 22:01:29  At 112.5% claim capcity (225Gi/200Gi)

相反,從集群中刪除一個(gè)PVC的時(shí)候,該工具會(huì)相應(yīng)展示提示信息。

...  At 112.5% claim capcity (225Gi/200Gi)  2018/02/14 11:30:36 PVC my-redis2-redis removed, size 100Gi  2018/02/14 11:30:36 Claim usage normal: max 200Gi at 125Gi  2018/02/14 11:30:36 *** Taking action ***

總結(jié)

這篇文章是進(jìn)行的系列的一部分,使用Go語言的官方k8s客戶端與API server進(jìn)行交互。和以前一樣,這個(gè)代碼會(huì)逐步的去實(shí)現(xiàn)一個(gè)命令行工具去監(jiān)聽指定namespace下面的PVC的大小。這個(gè)代碼實(shí)現(xiàn)了一個(gè)簡單的監(jiān)聽列表去觸發(fā)從服務(wù)器返回的資源事件。

到此,關(guān)于“如何使用Go構(gòu)建Kubernetes應(yīng)用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

名稱欄目:如何使用Go構(gòu)建Kubernetes應(yīng)用
分享URL:http://muchs.cn/article8/jcppop.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、網(wǎng)站維護(hù)、、小程序開發(fā)、商城網(wǎng)站做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管