直接使用Client

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  6. "k8s.io/client-go/kubernetes"
  7. "k8s.io/client-go/tools/clientcmd"
  8. "k8s.io/client-go/util/homedir"
  9. "log"
  10. "path/filepath"
  11. )
  12. func main() {
  13. home := homedir.HomeDir()
  14. kubeconfig := filepath.Join(home, ".kube", "config")
  15. config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
  16. if err != nil {
  17. panic(err)
  18. }
  19. // 初始化 client
  20. clientset, err := kubernetes.NewForConfig(config)
  21. if err != nil {
  22. log.Panic(err.Error())
  23. }
  24. stopCh := make(chan struct{})
  25. defer close(stopCh)
  26. list, err := clientset.AppsV1().Deployments("default").List(context.TODO(), v1.ListOptions{})
  27. if err == nil {
  28. for _, k := range list.Items {
  29. fmt.Println("deploy:",k.Name)
  30. }
  31. }
  32. }

这样查询数据会给APIServer带来负担。大多数情况下我们应该使用Informer机制。

基本原理如下图:
image.png
大致思路是给APIServer套了层缓存,在一开始获取到全量数据,然后基于etcd的watch机制,自动通知client-go的更新,client-go也会搞个本地缓存,所有更新也会作用于此缓存。后续对于资源的list操作将会走缓存。

informer 可以配置回调


import (
    "k8s.io/client-go/informers"
)

func main(){
    factory := informers.NewSharedInformerFactory(clientset, 60 * time.Second)
    podInformer := factory.Core().V1().Pods()

    informer := podInformer.Informer()
    informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
        AddFunc:    onAdd,
        UpdateFunc: onUpdate,
        DeleteFunc: onDelete,
    })

}

func onAdd(obj interface{}) 
    klog.Infof("add a pod: %+v", pod.Name)
}

// onUpdate // 此处省略 workqueue 的使用
func onUpdate(oldObj interface{}, newObj interface{}) {
    klog.Infof("update a pod")
}

func onDelete(obj interface{}) {
    klog.Infof("delete a pod: %+v\n", pod.Name)
}

pod发生变更时我们将会收到回调。

在CRD开发中,这个机制是非常必要的,我们需要把pod的当前状态和目标状态做对比,并尝试将当前状态修正为目标状态。