kubernetes client-go功能介紹

haiyux發表於2023-02-27

原味地址

https://haiyux.cc/2023/02/26/k8s-client-go/

client-go是什麼?

client-go是Kubernetes官方提供的Go語言客戶端庫,用於與Kubernetes API伺服器互動。使用client-go,您可以編寫Go語言程式來建立、修改和刪除Kubernetes物件,如Pod、Deployment、Service等。

作用

client-go的主要功能包括:

  1. 連線Kubernetes API伺服器:client-go提供了一個API客戶端,用於連線Kubernetes API伺服器。
  2. 物件管理:client-go提供了一組API,用於建立、讀取、更新和刪除Kubernetes物件,如Pod、Deployment、Service等。
  3. Watch API:client-go提供了一個Watch API,可以用於監視Kubernetes物件的變化。
  4. 名稱空間支援:client-go支援多個名稱空間,並提供了一組API,用於管理名稱空間。
  5. 認證和授權:client-go提供了一組API,用於執行身份驗證和授權,以確保只有授權的使用者才能對Kubernetes物件進行操作。

client-go是使用Kubernetes API的標準方式,是Kubernetes生態系統中的重要組成部分。

api client

client-go 中包含四種client,RestClient, ClientSetDynamicClientDiscoveryClient

ClientSetDynamicClientDiscoveryClient都是RestClient上的封裝

RestClient

RestClient是最基礎的客戶端,它基於HTTP請求進行了封裝,實現了RESTful API。使用RESTClient提供的RESTful方法,如Get()、Put()、Post()和Delete(),可以直接與API進行互動。同時,它支援JSON和Protocol Buffers,並支援所有原生資源和自定義資源定義(CRDs)。然而,為了更加優雅地處理API互動,一般需要進一步封裝,透過Clientset對RESTClient進行封裝,然後再對外提供介面和服務。

package main

import (
	"context"
	"fmt"
	"path/filepath"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)


func main() {
	// 使用kubeconfig生成配置
	config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config"))
	if err != nil {
		panic(err)
	}
	config.APIPath = "api"
	config.GroupVersion = &corev1.SchemeGroupVersion
	config.NegotiatedSerializer = scheme.Codecs

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

	rest := &corev1.PodList{}
	if err = restClient.Get().Namespace("default").Resource("pods").VersionedParams(&metav1.ListOptions{},
		scheme.ParameterCodec).Do(context.TODO()).Into(rest); err != nil {
		panic(err)
	}
	for _, v := range rest.Items {
		fmt.Printf("NameSpace: %v  Name: %v  Status: %v \n", v.Namespace, v.Name, v.Status.Phase)
	}
}

/*
結果
NameSpace: default  Name: nginx-76d6c9b8c-8ljkt  Status: Running 
NameSpace: default  Name: nginx-76d6c9b8c-jqv9h  Status: Running 
NameSpace: default  Name: nginx-76d6c9b8c-kr9d2  Status: Running 
NameSpace: default  Name: nginx-76d6c9b8c-m4g5l  Status: Running 
NameSpace: default  Name: nginx-76d6c9b8c-n8st9  Status: Running 
*/

ClientSet

ClientSet是在RestClient的基礎上封裝了對資源和版本的管理方法。資源可以理解為一個客戶端,而ClientSet是多個客戶端的集合。在操作資源物件時,需要指定Group和Version,然後根據資源獲取。然而,ClientSet不支援自定義資源定義(CRDs),但使用kubebuilder生成程式碼時,會生成相應的ClientSet。

package main

import (
	"context"
	"fmt"
	"path/filepath"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

func main() {
	ctx := context.Background()
	// 使用kubeconfig生成配置 ~/.kube/config
	config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config"))
	if err != nil {
		panic(err)
	}
	// 生成clientSet
	clientSet, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}
	nodeList, err := clientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
	if err != nil {
		panic(err)
	}
	for _, node := range nodeList.Items {
		fmt.Printf("nodeName: %v, status: %v \n", node.GetName(), node.GetCreationTimestamp())
	}
  // pod 是有namespace資源所以指定namespace 而node沒有
	pods, err := clientSet.CoreV1().Pods("default").List(ctx, metav1.ListOptions{})
	if err != nil {
		panic(err)
	}
	for _, v := range pods.Items {
		fmt.Printf("namespace: %v podName: %v status: %v \n", v.Namespace, v.Name, v.Status.Phase)
	}
}

/*
結果:
nodeName: minikube, status: 2023-01-27 18:45:35 +0800 CST 
nodeName: minikube-m02, status: 2023-02-26 21:19:30 +0800 CST 
nodeName: minikube-m03, status: 2023-02-26 21:19:38 +0800 CST 
namespace: default podName: nginx-76d6c9b8c-8ljkt status: Running 
namespace: default podName: nginx-76d6c9b8c-jqv9h status: Running 
namespace: default podName: nginx-76d6c9b8c-kr9d2 status: Running 
namespace: default podName: nginx-76d6c9b8c-m4g5l status: Running 
namespace: default podName: nginx-76d6c9b8c-n8st9 status: Running 
*/

DynamicClient

DynamicClient是一種動態客戶端,它可以對任何資源進行RESTful操作,包括自定義資源定義(CRD)。與ClientSet不同,DynamicClient返回的物件是一個map[string]interface{}。如果一個控制器需要控制所有的API,可以使用DynamicClient。目前,DynamicClient在垃圾回收器和名稱空間控制器中被廣泛使用。

DynamicClient的處理過程將Resource(例如PodList)轉換為unstructured型別。Kubernetes的所有資源都可以轉換為這個結構型別。處理完畢後,再將其轉換回PodList。整個轉換過程類似於介面轉換,即透過interface{}的斷言實現。

DynamicClient是一種動態的客戶端,它能處理Kubernetes所有的資源,但僅支援JSON

package main

import (
	"context"
	"fmt"
	"path/filepath"

	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

func main() {
	ctx := context.Background()
	// 使用kubeconfig生成配置 ~/.kube/config
	config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config"))
	if err != nil {
		panic(err)
	}
	// dynamicClient
	dynamicClient, err := dynamic.NewForConfig(config)
	if err != nil {
		panic(err)
	}
	// 定義組版本資源
	gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"}
	unStructObj, err := dynamicClient.Resource(gvr).Namespace("default").List(ctx, metav1.ListOptions{})
	if err != nil {
		panic(err)
	}
	podList := &apiv1.PodList{}

	if err = runtime.DefaultUnstructuredConverter.FromUnstructured(unStructObj.UnstructuredContent(), podList); err != nil {
		panic(err)
	}

	for _, v := range podList.Items {
		fmt.Printf("namespaces:%v  podName:%v status:%v \n", v.Namespace, v.Name, v.Status.Phase)
	}
}

/*
namespaces:default  podName:nginx-76d6c9b8c-8ljkt status:Running
namespaces:default  podName:nginx-76d6c9b8c-jqv9h status:Running
namespaces:default  podName:nginx-76d6c9b8c-kr9d2 status:Running
namespaces:default  podName:nginx-76d6c9b8c-m4g5l status:Running
namespaces:default  podName:nginx-76d6c9b8c-n8st9 status:Running
*/

其中,GVR(group,version,resource) 用於標識 Kubernetes API 中的資源型別,其中 Group 表示 API 群組,Version 表示 API 版本,Resource 表示資源型別。例如,Deployment 的 GVR 為 "apps/v1/deployments",其中 "apps" 是 API 群組,"v1" 是 API 版本,"deployments" 是資源型別。

DiscoveryClient

DiscoveryClient 是一個發現客戶端,它的主要作用是用於發現 API Server 支援的資源組、資源版本和資源資訊。在 Kubernetes 中,API Server 支援很多資源組、資源版本和資源資訊,我們可以透過使用 DiscoveryClient 來檢視這些資訊。此外,kubectl 的 API 版本和 API 資源也是透過 DiscoveryClient 來實現的。我們還可以將這些資訊快取到本地,以減輕 API 訪問的壓力。快取檔案預設儲存在 ./kube/cache./kube/http-cache 目錄下。

package main

import (
	"fmt"
	"path/filepath"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/homedir"
)

func main() {
	// 使用kubeconfig生成配置 ~/.kube/config
	config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config"))
	if err != nil {
		panic(err)
	}
	// 生成discoverClient
	discoverClient, err := discovery.NewDiscoveryClientForConfig(config)
	if err != nil {
		panic(err)
	}
	_, apiResourceList, err := discoverClient.ServerGroupsAndResources()
	for _, v := range apiResourceList {
		gv, err := schema.ParseGroupVersion(v.GroupVersion)
		if err != nil {
			panic(err)
		}
		for _, resource := range v.APIResources {
			fmt.Printf("name:%v group:%v version:%v\n", resource.Name, gv.Group, gv.Version)
		}
	}
}

/*
name:bindings group: version:v1
name:componentstatuses group: version:v1
name:configmaps group: version:v1
name:endpoints group: version:v1
name:events group: version:v1
name:limitranges group: version:v1
name:namespaces group: version:v1
name:namespaces/finalize group: version:v1
name:namespaces/status group: version:v1
name:nodes group: version:v1
name:nodes/proxy group: version:v1
name:nodes/status group: version:v1
name:persistentvolumeclaims group: version:v1
name:persistentvolumeclaims/status group: version:v1
name:persistentvolumes group: version:v1
name:persistentvolumes/status group: version:v1
name:pods group: version:v1
name:pods/attach group: version:v1
name:pods/binding group: version:v1
name:pods/ephemeralcontainers group: version:v1
name:pods/eviction group: version:v1
name:pods/exec group: version:v1
name:pods/log group: version:v1
name:pods/portforward group: version:v1
name:pods/proxy group: version:v1
name:pods/status group: version:v1
name:podtemplates group: version:v1
name:replicationcontrollers group: version:v1
name:replicationcontrollers/scale group: version:v1
name:replicationcontrollers/status group: version:v1
name:resourcequotas group: version:v1
name:resourcequotas/status group: version:v1
name:secrets group: version:v1
name:serviceaccounts group: version:v1
name:serviceaccounts/token group: version:v1
name:services group: version:v1
name:services/proxy group: version:v1
name:services/status group: version:v1
name:apiservices group:apiregistration.k8s.io version:v1
name:apiservices/status group:apiregistration.k8s.io version:v1
name:controllerrevisions group:apps version:v1
name:daemonsets group:apps version:v1
name:daemonsets/status group:apps version:v1
name:deployments group:apps version:v1
name:deployments/scale group:apps version:v1
name:deployments/status group:apps version:v1
name:replicasets group:apps version:v1
name:replicasets/scale group:apps version:v1
name:replicasets/status group:apps version:v1
name:statefulsets group:apps version:v1
name:statefulsets/scale group:apps version:v1
name:statefulsets/status group:apps version:v1
name:events group:events.k8s.io version:v1
name:tokenreviews group:authentication.k8s.io version:v1
name:localsubjectaccessreviews group:authorization.k8s.io version:v1
name:selfsubjectaccessreviews group:authorization.k8s.io version:v1
name:selfsubjectrulesreviews group:authorization.k8s.io version:v1
name:subjectaccessreviews group:authorization.k8s.io version:v1
name:horizontalpodautoscalers group:autoscaling version:v2
name:horizontalpodautoscalers/status group:autoscaling version:v2
name:horizontalpodautoscalers group:autoscaling version:v1
name:horizontalpodautoscalers/status group:autoscaling version:v1
name:horizontalpodautoscalers group:autoscaling version:v2beta2
name:horizontalpodautoscalers/status group:autoscaling version:v2beta2
name:cronjobs group:batch version:v1
name:cronjobs/status group:batch version:v1
name:jobs group:batch version:v1
name:jobs/status group:batch version:v1
name:certificatesigningrequests group:certificates.k8s.io version:v1
name:certificatesigningrequests/approval group:certificates.k8s.io version:v1
name:certificatesigningrequests/status group:certificates.k8s.io version:v1
name:ingressclasses group:networking.k8s.io version:v1
name:ingresses group:networking.k8s.io version:v1
name:ingresses/status group:networking.k8s.io version:v1
name:networkpolicies group:networking.k8s.io version:v1
name:networkpolicies/status group:networking.k8s.io version:v1
name:poddisruptionbudgets group:policy version:v1
name:poddisruptionbudgets/status group:policy version:v1
name:clusterrolebindings group:rbac.authorization.k8s.io version:v1
name:clusterroles group:rbac.authorization.k8s.io version:v1
name:rolebindings group:rbac.authorization.k8s.io version:v1
name:roles group:rbac.authorization.k8s.io version:v1
name:csidrivers group:storage.k8s.io version:v1
name:csinodes group:storage.k8s.io version:v1
name:csistoragecapacities group:storage.k8s.io version:v1
name:storageclasses group:storage.k8s.io version:v1
name:volumeattachments group:storage.k8s.io version:v1
name:volumeattachments/status group:storage.k8s.io version:v1
name:csistoragecapacities group:storage.k8s.io version:v1beta1
name:mutatingwebhookconfigurations group:admissionregistration.k8s.io version:v1
name:validatingwebhookconfigurations group:admissionregistration.k8s.io version:v1
name:customresourcedefinitions group:apiextensions.k8s.io version:v1
name:customresourcedefinitions/status group:apiextensions.k8s.io version:v1
name:priorityclasses group:scheduling.k8s.io version:v1
name:leases group:coordination.k8s.io version:v1
name:runtimeclasses group:node.k8s.io version:v1
name:endpointslices group:discovery.k8s.io version:v1
name:flowschemas group:flowcontrol.apiserver.k8s.io version:v1beta2
name:flowschemas/status group:flowcontrol.apiserver.k8s.io version:v1beta2
name:prioritylevelconfigurations group:flowcontrol.apiserver.k8s.io version:v1beta2
name:prioritylevelconfigurations/status group:flowcontrol.apiserver.k8s.io version:v1beta2
name:flowschemas group:flowcontrol.apiserver.k8s.io version:v1beta1
name:flowschemas/status group:flowcontrol.apiserver.k8s.io version:v1beta1
name:prioritylevelconfigurations group:flowcontrol.apiserver.k8s.io version:v1beta1
name:prioritylevelconfigurations/status group:flowcontrol.apiserver.k8s.io version:v1beta1
name:nodes group:metrics.k8s.io version:v1beta1
name:pods group:metrics.k8s.io version:v1beta1
*/

informer indexer lister機制

上圖展示了自定義控制器的工作方式。在虛線上方,是client-go包的informer和indexer工作方式。informer負責監聽Kubernetes API資源物件的變化,如建立、更新、刪除等操作,並將這些變化通知給indexer進行索引和快取。而indexer則是將API物件進行索引,以便在需要時快速地訪問它們。lister則是對indexer的封裝,提供了一種簡單的方式來獲取已經索引的物件列表,以供程式碼中的其他部分使用。這種分層結構的設計使得client-go可以高效地處理Kubernetes資源物件的變化,並在應用程式中方便地使用這些資源物件。

informer

Informer是Kubernetes API客戶端中一種重要的機制,它可以實現對資源物件的監視和事件通知。當Kubernetes叢集中的資源物件發生變化時,Informer可以及時地獲取到這些變化,並將這些變化以事件的形式通知給相關的監聽器。Informer透過呼叫API Server提供的REST介面,以及Kubernetes中定義的watch機制,實現了對叢集資源物件的全面監視。

下面是一個簡單的pod informer示例,用於監控所有pod的變化並將其放入佇列中,worker從佇列中取出pod並列印相關資訊。

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/util/workqueue"
)

func main() {
	// 獲取 kubeconfig 檔案路徑
	kubeconfigPath := os.Getenv("KUBECONFIG")
	if kubeconfigPath == "" {
		kubeconfigPath = os.Getenv("HOME") + "/.kube/config"
	}

	// 使用 kubeconfig 檔案建立 kubernetes 客戶端
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
	if err != nil {
		panic(err)
	}
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}

	// 建立 informer 工廠
	informerFactory := informers.NewSharedInformerFactory(clientset, time.Minute)

	// 建立 informer 物件
	podInformer := informerFactory.Core().V1().Pods()

	// 建立工作佇列
	queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())

	// 定義處理新增、更新和刪除事件的回撥函式
	podHandler := cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			key, err := cache.MetaNamespaceKeyFunc(obj)
			if err == nil {
				queue.Add(key)
			}
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			key, err := cache.MetaNamespaceKeyFunc(newObj)
			if err == nil {
				queue.Add(key)
			}
		},
		DeleteFunc: func(obj interface{}) {
			key, err := cache.MetaNamespaceKeyFunc(obj)
			if err == nil {
				queue.Add(key)
			}
		},
	}

	// 將回撥函式註冊到 informer 上
	podInformer.Informer().AddEventHandler(podHandler)

	// 啟動 informer
	stopCh := make(chan struct{})
	defer close(stopCh)
	informerFactory.Start(stopCh)

	// 等待 informer 同步完成
	if !cache.WaitForCacheSync(stopCh) {
		panic("同步 informer 快取失敗")
	}

	// 建立訊號處理程式,用於捕捉 SIGTERM 和 SIGINT 訊號
	signalCh := make(chan os.Signal, 1)
	signal.Notify(signalCh, syscall.SIGTERM, syscall.SIGINT)

	// 建立 worker 函式,用於處理佇列中的事件
	processNextItem := func() {
		obj, shutdown := queue.Get()
		if shutdown {
			return
		}

		// 轉換物件為 Pod
		key := obj.(string)
		podObj, exists, err := podInformer.Informer().GetIndexer().GetByKey(key)
		if err != nil {
			queue.Forget(obj)
			panic(fmt.Sprintf("獲取 Pod 失敗:%v", err))
		}

		if !exists {
			// 如果物件已經被刪除,就把它從佇列中移除
			queue.Forget(obj)
			return
		}

		// 在這裡新增處理 Pod 的邏輯
		pod := podObj.(*v1.Pod)
		fmt.Printf("處理 Pod: namespace:%v,podName:%v\n", pod.Namespace, pod.Name)

		// 處理完事件後,把它從佇列中移除
		queue.Forget(obj)
		return
	}

	// 啟動 worker
	go wait.Until(processNextItem, time.Second, stopCh)

	// 等待訊號
	<-signalCh
}

/*
處理 Pod: namespace:kube-system,podName:kindnet-h25kv
處理 Pod: namespace:kube-system,podName:kube-apiserver-minikube
處理 Pod: namespace:kube-system,podName:metrics-server-c9fb666df-zk4tb
處理 Pod: namespace:kubernetes-dashboard,podName:dashboard-metrics-scraper-b74747df5-4pb7w
處理 Pod: namespace:default,podName:nginx-76d6c9b8c-jqv9h
處理 Pod: namespace:default,podName:nginx-76d6c9b8c-m4g5l
處理 Pod: namespace:kube-system,podName:coredns-7f8cbcb969-48nz6
處理 Pod: namespace:kube-system,podName:kube-proxy-t766g
處理 Pod: namespace:kube-system,podName:kube-scheduler-minikube
處理 Pod: namespace:kube-system,podName:kindnet-44zl6
處理 Pod: namespace:kube-system,podName:kube-controller-manager-minikube
處理 Pod: namespace:kube-system,podName:kube-proxy-gq68w
處理 Pod: namespace:kube-system,podName:kube-proxy-l92vg
處理 Pod: namespace:kube-system,podName:storage-provisioner
處理 Pod: namespace:kubernetes-dashboard,podName:kubernetes-dashboard-57bbdc5f89-466rh
處理 Pod: namespace:default,podName:nginx-76d6c9b8c-kr9d2
處理 Pod: namespace:default,podName:nginx-76d6c9b8c-n8st9
處理 Pod: namespace:kube-system,podName:kindnet-w9f7t
處理 Pod: namespace:default,podName:nginx-76d6c9b8c-8ljkt
處理 Pod: namespace:kube-system,podName:etcd-minikube
處理 Pod: namespace:default,podName:nginx
處理 Pod: namespace:default,podName:ubuntu
*/

indexer

Indexer是client-go中用於本地快取資源物件的一種方式。它支援多種索引方式,並且可以使用函式func(obj interface{}) ([]string, error)進行索引。在檢索時,需要使用相同的indexName引數。藉助informer,indexer就可以維護一個特定資源的本地快取,例如pod、namespace等。這種方法省去了每次get pod都要訪問api-server的過程,從而減小了api-server的壓力。

// 如何使用索引器來檢索Pod物件
package main

import (
	"fmt"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/tools/cache"
)

const (
	NamespaceIndexName = "namespace" // 定義一個索引器名稱,用於按照名稱空間檢索Pod
	NodeNameIndexName  = "nodeName"  // 定義一個索引器名稱,用於按照節點名稱檢索Pod
)

// NamespaceIndexFunc是一個函式,用於從物件中提取名稱空間作為索引鍵
func NamespaceIndexFunc(obj interface{}) ([]string, error) {
	m, err := meta.Accessor(obj) // 獲取物件的後設資料
	if err != nil {
		return []string{""}, fmt.Errorf("object has no meta: %v", err)
	}
	return []string{m.GetNamespace()}, nil // 返回物件的名稱空間
}

// NodeNameIndexFunc是一個函式,用於從Pod物件中提取節點名稱作為索引鍵
func NodeNameIndexFunc(obj interface{}) ([]string, error) {
	pod, ok := obj.(*v1.Pod) // 判斷物件是否是Pod型別
	if !ok {
		return []string{}, nil // 如果不是,返回空切片
	}
	return []string{pod.Spec.NodeName}, nil // 如果是,返回Pod的節點名稱
}

func main() {
	index := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{
		NamespaceIndexName: NamespaceIndexFunc,
		NodeNameIndexName:  NodeNameIndexFunc,
	}) // 建立一個新的索引器,指定主鍵函式和輔助鍵函式

	pod1 := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "index-pod-1",
			Namespace: "default",
		},
		Spec: v1.PodSpec{NodeName: "node1"},
	} // 建立一個Pod物件,屬於default名稱空間和node1節點

	pod2 := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "index-pod-2",
			Namespace: "default",
		},
		Spec: v1.PodSpec{NodeName: "node2"},
	} // 建立另一個Pod物件,屬於default名稱空間和node2節點

	pod3 := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "index-pod-3",
			Namespace: "kube-system",
		},
		Spec: v1.PodSpec{NodeName: "node2"},
	} // 建立第三個Pod物件,屬於kube-system名稱空間和node2節點

	index.Add(pod1) // 將pod1新增到索引器中
	index.Add(pod2) // 將pod2新增到索引器中
	index.Add(pod3) // 將pod3新增到索引器中

	pods, err := index.ByIndex(NamespaceIndexName, "default") // 按照名稱空間為default檢索Pod列表
	if err != nil {
		panic(err)
	}
	for _, pod := range pods {
		fmt.Println(pod.(*v1.Pod).Name)
	} // 遍歷並列印檢索到的Pod名稱

	fmt.Println("*****************")

	pods, err = index.ByIndex(NodeNameIndexName, "node2") // 按照節點名稱為node2檢索Pod列表
	if err != nil {
		panic(err)
	}
	for _, pod := range pods {
		fmt.Println(pod.(*v1.Pod).Name)
	} // 遍歷並列印
}

/*
index-pod-2
index-pod-1
*****************
index-pod-2
index-pod-3
*/

lister

Lister是對Indexer的封裝,提供了一種方便的方式來獲取已經索引的Kubernetes資源物件列表。

具體而言,Lister是一個介面,包含了獲取所有已索引物件的列表以及根據名稱獲取單個物件的方法。這些方法可以幫助開發者在應用程式中快速訪問已經快取的資源物件,而無需直接與Indexer互動。

Lister的主要功能包括:

  1. 提供方便的介面:Lister介面的方法定義清晰簡潔,使用起來非常方便,可以快速地獲取已經索引的資源物件列表。
  2. 提高程式碼可讀性:透過使用Lister介面,程式碼可讀性得到提高。開發者可以更加專注於業務邏輯,而無需關注底層的Indexer實現細節。
  3. 提高程式碼複用性:由於Lister介面已經提供了通用的方法,因此可以更容易地在不同的程式碼模組中重用相同的邏輯,減少程式碼重複。

總之,Lister作為client-go包中的一個重要元件,可以幫助開發者更加高效地處理Kubernetes資源物件,提高程式碼的可讀性和可重用性。

package main

import (
	"fmt"
	"os"
	"time"

	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	// 獲取 kubeconfig 檔案路徑
	kubeconfigPath := os.Getenv("KUBECONFIG")
	if kubeconfigPath == "" {
		kubeconfigPath = os.Getenv("HOME") + "/.kube/config"
	}
	// 使用 kubeconfig 檔案建立 kubernetes 客戶端
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
	if err != nil {
		panic(err)
	}

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

	// 建立Informer
	factory := informers.NewSharedInformerFactory(clientset, time.Minute)
	podInformer := factory.Core().V1().Pods()

	// 建立Lister
	lister := podInformer.Lister()

	// 等待Informer同步完成
	stopCh := make(chan struct{})
	defer close(stopCh)

	factory.Start(stopCh)
	cache.WaitForCacheSync(stopCh, podInformer.Informer().HasSynced)

	// 獲取namespace為"default"的Pod物件
	podList, err := lister.Pods("default").List(labels.Everything())
	if err != nil {
		panic(err.Error())
	}
	// 列印Pod物件
	for _, pod := range podList {
		fmt.Printf("Pod name: %s, Namespace: %s\n", pod.Name, pod.Namespace)
	}
}

/*
Pod name: nginx-76d6c9b8c-m4g5l, Namespace: default
Pod name: nginx, Namespace: default
Pod name: ubuntu, Namespace: default
Pod name: nginx-76d6c9b8c-kr9d2, Namespace: default
Pod name: nginx-76d6c9b8c-n8st9, Namespace: default
Pod name: nginx-76d6c9b8c-8ljkt, Namespace: default
Pod name: nginx-76d6c9b8c-jqv9h, Namespace: default
*/

Reference

相關文章