1. 程式人生 > 其它 >k8s的client-go的使用

k8s的client-go的使用

學習地址:https://github.com/kubernetes/client-go
如果你要安裝最新的需要的環境是: go1.16+ ,使用下面的命令安裝:

go get k8s.io/client-go@latest

​ client-go 是用 Golang 語言編寫的官方程式設計式互動客戶端庫,提供對 Kubernetes API server 服務的互動訪問。它是 Kubernetes 的核心處理框架,k8s原始碼中已經集成了client-go的原始碼,無需單獨下載。原始碼路徑為:vendor/k8s.io/client-go。

​ k8s開發者使用client-go做二次開發,所以應該熟練掌握。

1、client-go原始碼結構

其原始碼目錄結構如下:

  1. discovery: 提供 DiscoveryClient 發現客戶端。

  2. dynamic: 提供 DynamicClient 動態客戶端。

  3. informers: 每種 K8S 資源的 Informer 實現。

  4. kubernetes: 提供 ClientSet 客戶端。

  5. listers: 為每一個 K8S 資源提供 Lister 功能,該功能對 Get 和 List 請求提供只讀的快取資料。

  6. plugin: 提供 OpenStack,GCP 和 Azure 等雲服務商授權外掛。

  7. rest: 提供 RESTClient 客戶端,對 K8S API Server 執行 RESTful 操作。

  8. scale: 提供 ScaleClient 客戶端,用於擴容或縮容 Deployment, Replicaset, Replication Controller 等資源物件。

  9. tools: 提供常用工具,例如 SharedInformer, Relector, DealtFIFO 及 Indexers。 提供 Client 查詢和快取機制,以減少想 kube-apiserver 發起的請求數等。主要子目錄為 /tools/cache。

  10. transport: 提供安全的 TCP 連線,支援 HTTP Stream,某些操作需要在客戶端和容器之間傳輸二進位制流,例如 exec,attach 等操作。該功能由內部的 SPDY 包提供支援。

  11. util: 提供常用方法。例如 WorkQueue 工作佇列,Certificate 證書管理等。

這章我們只簡單介紹下RESTClient、DiscoveryClient、DynamicClient、ClientSet這4中客戶端。

2、Client客戶端物件

client-go 支援4種Client客戶端物件 與 k8s api server 互動的方式,Client互動物件如下圖所示:

RESTClient 是最基礎的客戶端。RESTClient 對 HTTP Request 進行了封裝,實現了RESTful風格的api。ClientSet、DynamicClient及DiscoveryClient客戶端都是基於RESTClient 實現的。

  • RESTClient 客戶端

    ​ RESTful Client 是最基礎的客戶端,它主要是對 HTTP 請求進行了封裝,並且支援 JSON 和 Protobuf 格式資料。

  • DynamicClient 客戶端

    ​ DynamicClient 與 ClientSet 最大的不同之處是,ClientSet 僅能訪問k8s自帶的資源,不能直接訪問CRD自定義資源。DynamicClient 能處理k8s中的所有的資源物件,包括內建資源與CRD自定義資源。

  • ClientSet 客戶端

    ​ ClientSet 客戶端在 RESTClient 的基礎上封裝了對資源(Resource)和版本(Version)的管理方法。每個資源(Resource)可以理解為一個客戶端,而 ClientSet 則是多個客戶端的集合,每一個資源(Resource)和版本(Version)都以函式的方式暴露給開發者。ClientSet 只能處理k8s內建資源。

  • DiscoveryClient 客戶端

    ​ DiscoveryClient 發現客戶端,用於發現 kube-apiserver 所支援的資源組、資源版本、資源資訊(即Group、Versions、Resources)

​ 以上4種客戶端:RESTClient 、DynamicClient 、ClientSet 、DiscoveryClient 都可以通過kubeconfig配置資訊連線到指定的 kubernetes api server。

3、kubeconfig配置管理

kubeconfig 用於管理訪問 kube-apiserver 的配置資訊,k8s的其他元件都使用 kubeconfig 配置資訊來連線 kube-apiserver元件,例如:kubectl 訪問 kube-apiserver 時,會預設載入 kubeconfig 配置資訊。

​ kubeconfig 中儲存了叢集、使用者、名稱空間和身份驗證等資訊,在預設情況下,kubeconfig 存在在$HOME/.kube/config路徑下。配置資訊如下:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1URXhOakE0TXpJeU5Gb1hEVE14TVRFeE5EQTRNekl5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS0krClAyV3A1RDlTSk1NZllTNU1QMnFsQWx0MTh3OVptSkhjUlRxQ3R5Mms1NVloaVNrTzBXYzFaVEd2ZHZId0FqWjMKWnRFUVRwUFp0bXBaL3BUUEtNUkx5U1ZObU9PMjZhb2d0dTZJclpKbzMrQzVhTk9zQzVtTUZIUDRCcGE2aUk4Mwp0VWlORVRCRjhBbTlGdW9SVGhkZlVTelVNdUF6ZlJ5ZXU4L0NKcW4rVXJ5UjRhSE9ncHJxNmptNXZubDVqbUxoCnVMQjN5VTRMRVJUZDBmRWJIa09uRnR3cG42OEpOVnZLck1vajc3aHJ3RGdaTEVQQ0dQU0dxNEJ5dkRKQjhIWEoKb3JhUFBJVWNiNDlFcmx2TzJHOXFnODZDUWV4NEpBWEpSTldjcjlsblJtaEdoTkJwc1VXZ3VFRm1iMUxINjREdwpsMWVqbENURXJqblNqNjRZLzJzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJbDhJaStKWW1YOWdlVjVxaDUvWStIRFRhbjAKR2VldldQamtvdnFza0dReW1PT0hIak4rRHdPK2dZemVodGNUSUtPWVQvczhjOFlEUm1GTng4ZUI4RWVTRkJNaQpBWnMzaUE4b0NFTkdQUGF3QWdDbEFBTGp0SmNLOXR4RHdGdm5WcUsrUGk3bW52cmJtUVhxQzJRS1JRcEQ1VnlpCjZFeWRQdGlFZWRvSm93ZC9rdHh2UVlDSitGZFRBZHl3VVlxQzk1UDBLczhUanpEUDNaRVZnYkJER05kT0hIWVcKUXNOeG5DaDB0ZlpEbkl6ZCtCZ25SSDNLL1c0bWVCOXpYTzFrWVNLK2NGbFduWG40OUo1QmlEMkI3ZHk3eWt1Kwo0MUdvdGVrSjc3NXIySFlyR2dmaG9mYWtCenZnZEV2U1J0Y243OVkwTkZ6dmhUeFZIRWp5VExqTEY4TT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    server: https://127.0.0.1:16443
  name: cluster-10.9.244.32
contexts:
- context:
    cluster: cluster-10.9.244.32
    user: kubernetes-admin
  name: [email protected]
current-context: [email protected]
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQ3p5OXR6SzhhclV3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRFeE1UWXdPRE15TWpSYUZ3MHlNakV4TVRZd09ETXlNalphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXZ2UnhDaHVzblo1MU1zYU0KN01FZkVaUzdFb3ZlZUZTRTJ2MVZtOWt2U3dpVzVUclhqOG1LdWFjVWszZVdBMDdmVHdjMkJ3ZjNjVEFNazAxTQpHbU41bzEvcFdkam40TjdsdmxkeEZKclVVVkZGK3k4SUxySkVVdUhWdEtLUHZkM29jakxBTktwbGRCcWtrTTZVCmlKL0JKa3lvOXpPUWpBN0dUVmtBdTlQaFNDRktQUVhibjZHUUIrZW1LN1cxTFRkM1diQ2tacGE2NjVpUWhLRzMKKzhRMXJlMHFzcm9kQzNnV0Vna0N5TjNRUzIwRGowa0drMzJvWkp3Zkx5cUJOaUFNVzZ2azRpVjJqaEFTWDRYSwpEZ3pQVUNOUDFSSFkxZitkTEtBNzhoNXMremhTUi93VkxXajVPUlIvZ1hhcFRtZG80dy84NEpKbExwTWVScXJGCjQ0Y1Rhd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKNWZQMHVScWJhbkJLTnl5eVErVzVmaExQejYzK0hEVGNiTgptUTlKdFlNUk1MN3hkWkxRVXM1T1N1cWo4QWNiMWNXSXFNNkRhUmJVc2dlTFh6SEg3WDJjUzF5T1gvSFJ5L0ZPClBKdFcwRlhkbVhWWE1PbU5JWldwVWRmT08vYkx2eURhY2N4RkZ6alFkVksvdmg5Q2VqNkYvWnpVWXdkVlQ1eXQKenVYZ2llV2VxTFpzT1hZMlhyWmN5Vzg4Ky9VYUVaczdYR01xVEhSYjlUQi9iTTlxL0FnWHRscThlZEZvS1JkZwpYd2hFY0RzOWZuS2RwSG13QlVkV1lDcDFNNmVzamtObk9mMVU4Rk9OeXdUNm5xVG52VkgzQ1UzTkQxMSs5Y2IyCm1qSmVXK0QrRUd1VXZTR2tSamdLY1VYS1NCWXhwVWFoOWFWWGN3RjNnakhxa1RaaHZ0VT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBdnZSeENodXNuWjUxTXNhTTdNRWZFWlM3RW92ZWVGU0UydjFWbTlrdlN3aVc1VHJYCmo4bUt1YWNVazNlV0EwN2ZUd2MyQndmM2NUQU1rMDFNR21ONW8xL3BXZGpuNE43bHZsZHhGSnJVVVZGRit5OEkKTHJKRVV1SFZ0S0tQdmQzb2NqTEFOS3BsZEJxa2tNNlVpSi9CSmt5bzl6T1FqQTdHVFZrQXU5UGhTQ0ZLUFFYYgpuNkdRQitlbUs3VzFMVGQzV2JDa1pwYTY2NWlRaEtHMys4UTFyZTBxc3JvZEMzZ1dFZ2tDeU4zUVMyMERqMGtHCmszMm9aSndmTHlxQk5pQU1XNnZrNGlWMmpoQVNYNFhLRGd6UFVDTlAxUkhZMWYrZExLQTc4aDVzK3poU1Ivd1YKTFdqNU9SUi9nWGFwVG1kbzR3Lzg0SkpsTHBNZVJxckY0NGNUYXdJREFRQUJBb0lCQUdKYURwclJOREFldkdpQgpvWFlUNWdldEhrbG9KeGE5R1l5ZGJPbVBqRzlPSmtJODgyZ0l1MTN4ODRRYzFQUXhQSTA4dnBRU2cxMFdEWFFWCkhQeCtmZGtxL2txYmtKcmUwMkFkTTQ0VVRRVHhJbVZFalNkWUJCN1lXTFRvQWJjZVE2b0YvNzlnZ0U2enBrMDcKU1greElNKzBMbGJjaFRmT0tFOFFaM05XcHpMNXBWTEh2eEFyYWNNMWg0K1d4NDZnNHJRN3JwS1BUa2VFa1loYwo3amE2TWl6UjEvZDFUNERqa2JGUnU3SVNSNVpvWithL0o2dGkzSStoc0lqaU0yeE5sQ0Y0MXVZa0lDSkhnMkZYCnlyZkYwZm1YS2c1T1oweWFHTUhTdUNpbE9UUUlnYndMN3RMMWR0bU5YaTBvTzdZbXF5MHFaSVdlV1BRVitJUWkKOXREdXFVa0NnWUVBOXg2TzJCaVBqdzAyUENYQ0xhcHZpVHNCeFRmNVFCbVpkZlEvNFJubGY1T3IwZ2ZmdmgzbApNUDBYYUZraWdaUW83NmJvZlFRd0VNZWdnRkFXNkhFSkVOQTd4Z2NsVlFxTHVST2pUTVNkRVUraUl1eXZ0VFZmClJZYTUxODdCTEFwWThnRHQzQjhjVlN6RGQvdlIrVmJ4MFNJVGdTbVFGSUdtdC9TWmdnMFp4cjhDZ1lFQXhkRXUKeXIwaUxHNWtyRHN3VmxVc3RsU2lHQmxBZEhOMld1eEFncmw5UTdSWEt0V3B0allqTnhMdVJoU1dLOEYzYjBlQwoyaUQxWTljMkgyNmJYelA1OEorTkZyMmNzYmJKdFNmWi9xcXE3Q3V0K2liUng1Q0IyQm1UZDVpWWhqWTNRUjQzCnlOWFhhR2dzUzFQQWt6Q1dVcmVuVHh6bzFBNzRnN05PZjhLVGFsVUNnWUFOaDNyQ2tmV3FHMHNRMS9CZGw2c3IKbEROd25MUGtzb0lZVnhyNE0vYkFtVkVhMnB1QlNSbTNLT1FUTG00Wk1nZGJ0NE9hOUpPOUYzRE9GWlJyZldURgpxdURhNHFGRW1xTXpxc09SL0dHdEJQTVhmbVhRUWUvSldxcnFDY1BCcVg5ZElIZmxTVDYvMndlSWxoelV6ZEhIClpWbzBCQmFEU09YYnhHUnpIa3grK1FLQmdDeXZOL2FzQ3BBbXo2N29IOThnbGwwSmVTUWdjQ0xlQWhvL3k4SzcKeThRRGRMMUVUblhPZk4zdjlNcjMwNFJHeTRmamkzZGlnb3Z2RFZiRVVXeUwvU1dScFBsQ0U2ZEJOd2NvM1dGZApoQWFkUjB0K2dWeW5FKzJRdVhNR2tVMmY2Wk5ZRkJuVjFEYk5jVlFDc3ptTWZDaHJPK3Z2QjlqL0dMd0hRUEF6Ckw4R1JBb0dCQVBVSnZ5NHlsRG1TdkJheFZrdGdXRjRYc096cytCR0sweFI0VEdZa0JNODhRTHFLTVU1RFZCV3MKdjVQQ2xFMVcxOHVJWkZMTzdGUXd5U1ZwZ0cwZ3NOcVBDRjdwVVZmRjg0VkFiWmxCdGJNSWdCcFRIMjU0M2FHegpQMGZNdnFEaU91bksxa0VaWDh4YkdMTHFXZjBBTGgwUkVmbDBTL3pmZ1RDUDBzTTZtKzdJCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

kubeconfig配置資訊通常包含3個部分,分別介紹如下:

  • clusters:定義kubernetes叢集資訊,例如kube-apiserver 的服務地址及叢集的證書資訊等。
  • users:定義kubernetes叢集使用者身份驗證的客戶端憑據,例如 client-certificate、client-key等資訊。
  • contexts:定義kubernetes叢集使用者資訊和名稱空間等,用於將請求傳送到指定的叢集。

client-go會讀取 kubeconfig 配置資訊並生成config物件,用於與kube-apiserver通訊,程式碼如下:

config, err := clientcmd.BuildConfigFromFlags("", "/root/.kube/config")
if err != nil {
    panic(err.Error())
}

在上述程式碼中,clientcmd.BuildConfigFromFlags 函式會讀取kubeconfig配置資訊並例項化 rest.Config 物件。

4、RESTClient客戶端

RESTClient是最基礎的客戶端,其他的客戶端都是基於它實現的。RESTClient對HTTP Request 進行了封裝,實現了Restful 風格的api。

​ 類似於kubectl命令,通過RESTClient列出所有執行pod資源物件,程式碼如下:

package main

import (
    "flag"
    "fmt"
    "context"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "path/filepath"
    "k8s.io/client-go/kubernetes/scheme"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func main() {

    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    config.APIPath = "api"
    config.GroupVersion = &corev1.SchemeGroupVersion
    config.NegotiatedSerializer = scheme.Codecs

    restClient, err := rest.RESTClientFor(config)
    if err != nil {
        panic(err.Error())
    }

    result := &corev1.PodList{}
    err = restClient.Get().
        Namespace("whalebase").
        Resource("pods").
        VersionedParams(&metav1.ListOptions{Limit: 500}, scheme.ParameterCodec).
        Do(context.TODO()).
        Into(result)

    for _, d := range result.Items {
        fmt.Printf("namespace:%v \t name:%v \t status:%+v\n", d.Namespace, d.Name, d.Status.Phase)
    }
}

執行以上程式碼,列出 whalebase 名稱空間下所有 pod 資源物件的相關資訊。首先載入 kubeconfig 配置資訊,並設定 config.APIPath 請求的 HTTP 路徑。然後設定 config.GroupVersion 請求的資源組/資源版本。最後設定 config.NegotiatedSerializer 資料的編解碼器。

​ rest.RESTClientFor 函式通過 kubeconfig 配置資訊例項化 RESTClient 物件,RESTClient 物件構建 HTTP 請求引數,例如GET函式設定請求方法為get操作,它還支援post、put、delete、patch 等請求方法。Namespace 函式設定名稱空間。 Resource 函式設定請求的資源名稱。VersionedParams 函式將一些查詢選項(如limit、TimeoutSeconds等)新增到請求引數中。通過Do函式執行該請求,並將 kube-apiserver 返回的結果(Result物件)解析到 corev1.PodList 物件中。最終格式化輸出結果。

5、ClientSet 客戶端

RESTClient 最基礎的客戶端,使用時需要指定 Resource 和 Version 等資訊,編寫程式碼時需要提前知道 Resource 所在的 Group 和對應的 Version 資訊。相比 RESTClient ,ClientSet 使用起來更加便捷,一般情況下,開發者對kubernetes進行二次開發時通常使用 ClientSet。

ClientSet 在 RESTClient 的基礎上封裝了對 Resource 和 Version 的管理方法。每一個 Resource 可以理解為一個客戶端, 而ClientSet 則是多個客戶端的集合,每一個 Resource 和 Version 都以函式的形式暴露給開發者。例如 ClientSet 提供的 RbacV1、CoreV1、NetworkingV1 等介面函式,多個 ClientSet 多資源集合如下圖:

與 api-server 互動,示例程式碼如下:

package main

import (
    "context"
    "flag"
    "fmt"
    v1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/util/json"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "path/filepath"
)

func main() {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    // create the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        panic(err.Error())
    }
    fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))

    // 獲取mysql的pod
    namespace := "whalebase"
    pod := "mysql-0"
    mysqlPod, err := clientset.CoreV1().Pods(namespace).Get(context.TODO(), pod, metav1.GetOptions{})
    if errors.IsNotFound(err) {
        fmt.Printf("Pod %s in namespace %s not found\n", pod, namespace)
    } else if statusError, isStatus := err.(*errors.StatusError); isStatus {
        fmt.Printf("Error getting pod %s in namespace %s: %v\n",
            pod, namespace, statusError.ErrStatus.Message)
    } else if err != nil {
        panic(err.Error())
    } else {
        fmt.Printf("Found pod %s in namespace %s\n", pod, namespace)
        bytes, _ := json.Marshal(mysqlPod)
        fmt.Println("pod資訊:",string(bytes))
    }

    fmt.Println("--------------------------------")
    // 獲取mysql的StatefulSets
    sts, _ := clientset.AppsV1().StatefulSets(namespace).Get(context.TODO(), "mysql", metav1.GetOptions{})
    bytes, _ := json.Marshal(sts)
    fmt.Println("sts資訊:",string(bytes))
    fmt.Println("--------------------------------")
    //建立pod
    var nginxPod *v1.Pod = &v1.Pod {
        TypeMeta: metav1.TypeMeta{Kind:"Pod",APIVersion:"v1"},
        ObjectMeta: metav1.ObjectMeta{Name:"nginx-pod"},
        Spec: v1.PodSpec{
            Containers: []v1.Container{
                v1.Container{
                    Name: "nginx",
                    Image: "nginx:1.8",
                },
            },
        },
    }
    _, err = clientset.CoreV1().Pods("default").Create(context.TODO(), nginxPod, metav1.CreateOptions{})
    if err != nil {
        fmt.Println(err)
    }
}

6、DynamicClient 客戶端

DynamicClient 是一種動態客戶端,它可以與任意 kubernetes 資源進行 RESTful 操作,包括 CRD 自定義資源。DynamicClient 與 ClientSet 操作類似,同樣封裝了RESTClient,同樣提供了Create、Update、Get、List、Watch、Patch 等方法。

​ DynamicClient 與 ClientSet 最大的不同之處是,ClientSet 僅能訪問 kubernetes 自帶的資源,不能訪問 CRD 自定義資源。 ClientSet 需要預先 實現每種 Resource、Version 的操作,其內部都是結構化資料(即已知資料結構)。而 DynamicClient 內部實現了 Unstructured,用於處理非結構化資料結構(即無法預先提前預知資料結構),這也是 DynamicClient 能夠處理CRD自定義資源的關鍵。

​ DynamicClient 的處理過程將 Resource (例如PodList)轉換成 Unstructured 結構型別, kubernetes 的所有 Resource 都可以轉化成該結構型別。處理完成後,再將 Unstructured 轉換成 PodList 。整個過程類似於Go語言的interface{}斷言轉換過程,另外, Unstructured 結構型別是通過 map[string]interface{} 轉換的。

package main

import (
    "context"
    "flag"
    "fmt"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/client-go/dynamic"
    "k8s.io/client-go/tools/clientcmd"
    "path/filepath"
    "k8s.io/client-go/util/homedir"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime/schema"
)

func main() {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    dynamicClient, err := dynamic.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    gvr := schema.GroupVersionResource{Version: "v1",Resource: "pods"}
    unstructuredList, err := dynamicClient.Resource(gvr).Namespace("whalebase").List(context.TODO(), metav1.ListOptions{Limit: 500})
    if err != nil {
        panic(err.Error())
    }

    podList := &corev1.PodList{}
    err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredList.UnstructuredContent(),podList)
    if err != nil {
        panic(err.Error())
    }

    for _, d := range podList.Items {
        fmt.Printf("namespace:%v \t name:%v \t status:%+v\n", d.Namespace, d.Name, d.Status.Phase)
    }
}

dynamicClient.Resource(gvr) 函式用於設定請求的資源組、資源版本、資源名稱。Namespace 函式用於設定請求的名稱空間。List 函式用於獲取 pod 列表。得到的pod列表為 unstructured.UnstructuredList 指標型別,然後通過 runtime.DefaultUnstructuredConverter 函式將 unstructured.UnstructuredList 轉換成 PodList 型別。

7、DiscoveryClient客戶端

DiscoveryClient 是發現客戶端,它主要用於發現 Kubernetes API Server 所支援的資源組、資源版本、資源資訊,開發者在開發過程中很難記住所有的資訊,此時可以通過 DiscoveryClient 檢視所支援的資源組、資源版本、資源資訊。

​ kubectl api-versions 和 api-resources 命令輸出也是通過 DiscoveryClient 實現的。另外, DiscoveryClient 同樣在 RESTClient 的基礎上進行了封裝。

​ DiscoveryClient 除了可以發現 Kubernetes API Server 所支援的資源組、資源版本、資源資訊,還可以將這些資訊儲存到本地,用於本地快取(Cache),以減輕對 Kubernetes API Server 訪問的壓力。在執行 Kubernetes 元件的機器刪,快取資訊預設儲存於~/.kube/cache 和 ~/.kube/http-cache 下。

​ 類似於kubectl命令,通過 DiscoveryClient 列出 Kubernetes API Server 所支援的資源組、資源版本、資源資訊,程式碼如下:

package main

import (
    "flag"
    "fmt"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "k8s.io/client-go/discovery"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "path/filepath"
)

func main() {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    _, APIResourceList, err := discoveryClient.ServerGroupsAndResources()
    if err != nil {
        panic(err.Error())
    }

    for _, list := range APIResourceList{
        gv, err := schema.ParseGroupVersion(list.GroupVersion)
        if err != nil {
            panic(err.Error())
        }

        for _, resource := range list.APIResources {
            fmt.Printf("name: %v, group: %v, version: %v\n", resource.Name, gv.Group, gv.Version)
        }
    }
}

執行以上程式碼,列出 Kubernetes API Server 所支援的資源組、資源版本、資源資訊。首先載入 kubeconfig 配置資訊,discovery.NewDiscoveryClientForConfig 通過 kubeconfig 配置資訊例項化 discoveryclient 物件,該物件是用於發現 Kubernetes API Server 所支援的資源組、資源版本、資源資訊的客戶端。

​ discoveryClient.ServerGroupsAndResources 函式會返回 Kubernetes API Server 所支援的 資源組、資源版本、資源資訊(即APIResourceList),通過遍歷 APIResourceList 輸出資訊。