k8s client-go 源码分析(一)

1,139 阅读7分钟

k8s整个的交互图

image.png

1. client-go说明

client-go 是 一个调用k8s集群资源对象api的客户端,即通过client-go实现对k8s集群中资源对象(包括deployment、service、ingress、replicaSet、pod、namespace等)的增删改查,大部分对k8s进行前置API封装的二次开发都是通过client-go这个第三方包来实现的。

client-go官方文档:github.com/kubernetes/…

1.1 client-go 示例应用代码

git clone https://github.com/huweihuang/client-go.git
cd client-go
#保证本地HOME目录有配置kubernetes集群的配置文件
go run client-go.go

client-go.go

package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"time"

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

func main() {
	var kubeconfig *string
	if home := 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()
	// uses the current context in kubeconfig
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		panic(err.Error())
	}
	// creates the clientset
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}
	for {
		pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
		if err != nil {
			panic(err.Error())
		}
		fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
		time.Sleep(10 * time.Second)
	}
}

func homeDir() string {
	if h := os.Getenv("HOME"); h != "" {
		return h
	}
	return os.Getenv("USERPROFILE") // windows
}

运行结果如下:

➜ go run client-go.go\
There are 9 pods in the cluster\
There are 7 pods in the cluster\
There are 7 pods in the cluster\
There are 7 pods in the cluster\
There are 7 pods in the cluster\

2. client-go源码分析

2.1 client-go的代码结构

client-go1.PNG

  • The kubernetes package contains the clientset to access Kubernetes API.
  • The discovery package is used to discover APIs supported by a Kubernetes API server.
  • The dynamic package contains a dynamic client that can perform generic operations on arbitrary Kubernetes API objects.
  • The transport package is used to set up auth and start a connection.
  • The tools/cache package is useful for writing controllers.

2.2 kubeconfig

kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")\

获取k8s配置文件kubeconfig的绝对路径,一般路径为

$HOME/.kube/config

该文件主要用来配置本地连接的k8s的集群。 客户端的启动是需要配置文件的,要知道去链接哪个apiserver,使用账户信息等等,这个配置文件一般保存在~/.kube/config。 config内容如下:

apiVersion: v1
clusters:
- cluster:
    server: http://<kube-master-ip>:8080
  name: k8s
contexts:
- context:
    cluster: k8s
    namespace: default
    user: ""
  name: default
current-context: default
kind: Config
preferences: {}
users: []

2.3 rest.Config

通过参数(masterde url或者k8s的kubeconfig的路径)和BuildConfigFromFlags方法获取rest.Config对象,一般是通过参数kubeconfig的路径。

config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)\

k8s.io/client-go/t…

BuildConfigFromFlags函数源码

// BuildConfigFromFlags is a helper function that builds configs from a master
// url or a kubeconfig filepath. These are passed in as command line flags for cluster
// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
// to the default config.
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
	if kubeconfigPath == "" && masterUrl == "" {
		glog.Warningf("Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.")
		kubeconfig, err := restclient.InClusterConfig()
		if err == nil {
			return kubeconfig, nil
		}
		glog.Warning("error creating inClusterConfig, falling back to default config: ", err)
	}
	return NewNonInteractiveDeferredLoadingClientConfig(
		&ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
		&ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig()
}

2.4 clientSet

通过*rest.Config参数和NewForConfig方法获取clientSet对象,clientSet是多个client的集合,每个client可能包含不同版本版本的方法调用。

clientset, err := kubernetes.NewForConfig(config)

2.4.1 NewForConfig

NewForConfig函数就是初始化clientSet中的每一个client。

k8s.io/client-go/k…

// NewForConfig creates a new Clientset for the given config.
// If config's RateLimiter is not set and QPS and Burst are acceptable,
// NewForConfig will generate a rate-limiter in configShallowCopy.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(c *rest.Config) (*Clientset, error) {
   configShallowCopy := *c

   // share the transport between all clients
   httpClient, err := rest.HTTPClientFor(&configShallowCopy)
   if err != nil {
      return nil, err
   }

   return NewForConfigAndClient(&configShallowCopy, httpClient)
}

NewForConfigAndClient函数将配置文件和httpclient入参传入,初始化每一种客户端。

// NewForConfigAndClient creates a new Clientset for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
// If config's RateLimiter is not set and QPS and Burst are acceptable,
// NewForConfigAndClient will generate a rate-limiter in configShallowCopy.
func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) {
   configShallowCopy := *c
   if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
      if configShallowCopy.Burst <= 0 {
         return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
      }
      configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
   }

   var cs Clientset
   var err error
   cs.admissionregistrationV1, err = admissionregistrationv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.admissionregistrationV1beta1, err = admissionregistrationv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.internalV1alpha1, err = internalv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.appsV1, err = appsv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.appsV1beta1, err = appsv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.appsV1beta2, err = appsv1beta2.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.authenticationV1, err = authenticationv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.authenticationV1beta1, err = authenticationv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.authorizationV1, err = authorizationv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.authorizationV1beta1, err = authorizationv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.autoscalingV1, err = autoscalingv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.autoscalingV2, err = autoscalingv2.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.autoscalingV2beta1, err = autoscalingv2beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.autoscalingV2beta2, err = autoscalingv2beta2.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.batchV1, err = batchv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.batchV1beta1, err = batchv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.certificatesV1, err = certificatesv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.certificatesV1beta1, err = certificatesv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.coordinationV1beta1, err = coordinationv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.coordinationV1, err = coordinationv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.coreV1, err = corev1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.discoveryV1, err = discoveryv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.discoveryV1beta1, err = discoveryv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.eventsV1, err = eventsv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.eventsV1beta1, err = eventsv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.extensionsV1beta1, err = extensionsv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.flowcontrolV1alpha1, err = flowcontrolv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.flowcontrolV1beta1, err = flowcontrolv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.flowcontrolV1beta2, err = flowcontrolv1beta2.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.networkingV1, err = networkingv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.networkingV1beta1, err = networkingv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.nodeV1, err = nodev1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.nodeV1alpha1, err = nodev1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.nodeV1beta1, err = nodev1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.policyV1, err = policyv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.policyV1beta1, err = policyv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.rbacV1, err = rbacv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.rbacV1beta1, err = rbacv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.rbacV1alpha1, err = rbacv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.schedulingV1alpha1, err = schedulingv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.schedulingV1beta1, err = schedulingv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.schedulingV1, err = schedulingv1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.storageV1beta1, err = storagev1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.storageV1, err = storagev1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   cs.storageV1alpha1, err = storagev1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }

   cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient)
   if err != nil {
      return nil, err
   }
   return &cs, nil
}

2.4.2 clientset的结构体

k8s.io/client-go/k…

// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
   *discovery.DiscoveryClient
   admissionregistrationV1      *admissionregistrationv1.AdmissionregistrationV1Client
   admissionregistrationV1beta1 *admissionregistrationv1beta1.AdmissionregistrationV1beta1Client
   internalV1alpha1             *internalv1alpha1.InternalV1alpha1Client
   appsV1                       *appsv1.AppsV1Client
   appsV1beta1                  *appsv1beta1.AppsV1beta1Client
   appsV1beta2                  *appsv1beta2.AppsV1beta2Client
   authenticationV1             *authenticationv1.AuthenticationV1Client
   authenticationV1beta1        *authenticationv1beta1.AuthenticationV1beta1Client
   authorizationV1              *authorizationv1.AuthorizationV1Client
   authorizationV1beta1         *authorizationv1beta1.AuthorizationV1beta1Client
   autoscalingV1                *autoscalingv1.AutoscalingV1Client
   autoscalingV2                *autoscalingv2.AutoscalingV2Client
   autoscalingV2beta1           *autoscalingv2beta1.AutoscalingV2beta1Client
   autoscalingV2beta2           *autoscalingv2beta2.AutoscalingV2beta2Client
   batchV1                      *batchv1.BatchV1Client
   batchV1beta1                 *batchv1beta1.BatchV1beta1Client
   certificatesV1               *certificatesv1.CertificatesV1Client
   certificatesV1beta1          *certificatesv1beta1.CertificatesV1beta1Client
   coordinationV1beta1          *coordinationv1beta1.CoordinationV1beta1Client
   coordinationV1               *coordinationv1.CoordinationV1Client
   coreV1                       *corev1.CoreV1Client
   discoveryV1                  *discoveryv1.DiscoveryV1Client
   discoveryV1beta1             *discoveryv1beta1.DiscoveryV1beta1Client
   eventsV1                     *eventsv1.EventsV1Client
   eventsV1beta1                *eventsv1beta1.EventsV1beta1Client
   extensionsV1beta1            *extensionsv1beta1.ExtensionsV1beta1Client
   flowcontrolV1alpha1          *flowcontrolv1alpha1.FlowcontrolV1alpha1Client
   flowcontrolV1beta1           *flowcontrolv1beta1.FlowcontrolV1beta1Client
   flowcontrolV1beta2           *flowcontrolv1beta2.FlowcontrolV1beta2Client
   networkingV1                 *networkingv1.NetworkingV1Client
   networkingV1beta1            *networkingv1beta1.NetworkingV1beta1Client
   nodeV1                       *nodev1.NodeV1Client
   nodeV1alpha1                 *nodev1alpha1.NodeV1alpha1Client
   nodeV1beta1                  *nodev1beta1.NodeV1beta1Client
   policyV1                     *policyv1.PolicyV1Client
   policyV1beta1                *policyv1beta1.PolicyV1beta1Client
   rbacV1                       *rbacv1.RbacV1Client
   rbacV1beta1                  *rbacv1beta1.RbacV1beta1Client
   rbacV1alpha1                 *rbacv1alpha1.RbacV1alpha1Client
   schedulingV1alpha1           *schedulingv1alpha1.SchedulingV1alpha1Client
   schedulingV1beta1            *schedulingv1beta1.SchedulingV1beta1Client
   schedulingV1                 *schedulingv1.SchedulingV1Client
   storageV1beta1               *storagev1beta1.StorageV1beta1Client
   storageV1                    *storagev1.StorageV1Client
   storageV1alpha1              *storagev1alpha1.StorageV1alpha1Client
}

2.4.3 clientset的Interface

clientset实现这个Interface,因此可以通过以下方法获得具体的client,例如:

pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})

clientset的Interface k8s.io/client-go/k…

type Interface interface {
   Discovery() discovery.DiscoveryInterface
   AdmissionregistrationV1() admissionregistrationv1.AdmissionregistrationV1Interface
   AdmissionregistrationV1beta1() admissionregistrationv1beta1.AdmissionregistrationV1beta1Interface
   InternalV1alpha1() internalv1alpha1.InternalV1alpha1Interface
   AppsV1() appsv1.AppsV1Interface
   AppsV1beta1() appsv1beta1.AppsV1beta1Interface
   AppsV1beta2() appsv1beta2.AppsV1beta2Interface
   AuthenticationV1() authenticationv1.AuthenticationV1Interface
   AuthenticationV1beta1() authenticationv1beta1.AuthenticationV1beta1Interface
   AuthorizationV1() authorizationv1.AuthorizationV1Interface
   AuthorizationV1beta1() authorizationv1beta1.AuthorizationV1beta1Interface
   AutoscalingV1() autoscalingv1.AutoscalingV1Interface
   AutoscalingV2() autoscalingv2.AutoscalingV2Interface
   AutoscalingV2beta1() autoscalingv2beta1.AutoscalingV2beta1Interface
   AutoscalingV2beta2() autoscalingv2beta2.AutoscalingV2beta2Interface
   BatchV1() batchv1.BatchV1Interface
   BatchV1beta1() batchv1beta1.BatchV1beta1Interface
   CertificatesV1() certificatesv1.CertificatesV1Interface
   CertificatesV1beta1() certificatesv1beta1.CertificatesV1beta1Interface
   CoordinationV1beta1() coordinationv1beta1.CoordinationV1beta1Interface
   CoordinationV1() coordinationv1.CoordinationV1Interface
   CoreV1() corev1.CoreV1Interface
   DiscoveryV1() discoveryv1.DiscoveryV1Interface
   DiscoveryV1beta1() discoveryv1beta1.DiscoveryV1beta1Interface
   EventsV1() eventsv1.EventsV1Interface
   EventsV1beta1() eventsv1beta1.EventsV1beta1Interface
   ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Interface
   FlowcontrolV1alpha1() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface
   FlowcontrolV1beta1() flowcontrolv1beta1.FlowcontrolV1beta1Interface
   FlowcontrolV1beta2() flowcontrolv1beta2.FlowcontrolV1beta2Interface
   NetworkingV1() networkingv1.NetworkingV1Interface
   NetworkingV1beta1() networkingv1beta1.NetworkingV1beta1Interface
   NodeV1() nodev1.NodeV1Interface
   NodeV1alpha1() nodev1alpha1.NodeV1alpha1Interface
   NodeV1beta1() nodev1beta1.NodeV1beta1Interface
   PolicyV1() policyv1.PolicyV1Interface
   PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface
   RbacV1() rbacv1.RbacV1Interface
   RbacV1beta1() rbacv1beta1.RbacV1beta1Interface
   RbacV1alpha1() rbacv1alpha1.RbacV1alpha1Interface
   SchedulingV1alpha1() schedulingv1alpha1.SchedulingV1alpha1Interface
   SchedulingV1beta1() schedulingv1beta1.SchedulingV1beta1Interface
   SchedulingV1() schedulingv1.SchedulingV1Interface
   StorageV1beta1() storagev1beta1.StorageV1beta1Interface
   StorageV1() storagev1.StorageV1Interface
   StorageV1alpha1() storagev1alpha1.StorageV1alpha1Interface
}

2.5 CoreV1Client

我们以clientset中的CoreV1Client为例做分析,

通过传入rest.Confighttp.Client初始化CoreV1Client对象。

github.com/kubernetes/…

cs.coreV1, err = corev1.NewForConfigAndClient(&configShallowCopy, httpClient)
// NewForConfigAndClient creates a new CoreV1Client for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CoreV1Client, error) {
   config := *c
   if err := setConfigDefaults(&config); err != nil {
      return nil, err
   }
   client, err := rest.RESTClientForConfigAndClient(&config, h)
   if err != nil {
      return nil, err
   }
   return &CoreV1Client{client}, nil
}

covev1.NewForConfigAndClient的方法本质是调用了rest.RESTClientForConfigAndClient(&config, h)方法创建*RESTClient对象,即coveV1Client的本质就是一个RESTClient对象。

2.5.1 CoreV1Client结构体

以下是CoreV1Client结构体的定义: github.com/kubernetes/…

// CoreV1Client is used to interact with features provided by the  group.
type CoreV1Client struct {
   restClient rest.Interface
}

CoreV1Client实现了CoreV1Interface的接口,即以下方法,从而对k8s的资源对象进行增删改查。

func (c *CoreV1Client) ComponentStatuses() ComponentStatusInterface {
   return newComponentStatuses(c)
}

func (c *CoreV1Client) ConfigMaps(namespace string) ConfigMapInterface {
   return newConfigMaps(c, namespace)
}

func (c *CoreV1Client) Endpoints(namespace string) EndpointsInterface {
   return newEndpoints(c, namespace)
}

func (c *CoreV1Client) Events(namespace string) EventInterface {
   return newEvents(c, namespace)
}

func (c *CoreV1Client) LimitRanges(namespace string) LimitRangeInterface {
   return newLimitRanges(c, namespace)
}

func (c *CoreV1Client) Namespaces() NamespaceInterface {
   return newNamespaces(c)
}

func (c *CoreV1Client) Nodes() NodeInterface {
   return newNodes(c)
}

func (c *CoreV1Client) PersistentVolumes() PersistentVolumeInterface {
   return newPersistentVolumes(c)
}

func (c *CoreV1Client) PersistentVolumeClaims(namespace string) PersistentVolumeClaimInterface {
   return newPersistentVolumeClaims(c, namespace)
}

func (c *CoreV1Client) Pods(namespace string) PodInterface {
   return newPods(c, namespace)
}

func (c *CoreV1Client) PodTemplates(namespace string) PodTemplateInterface {
   return newPodTemplates(c, namespace)
}

func (c *CoreV1Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
   return newReplicationControllers(c, namespace)
}

func (c *CoreV1Client) ResourceQuotas(namespace string) ResourceQuotaInterface {
   return newResourceQuotas(c, namespace)
}

func (c *CoreV1Client) Secrets(namespace string) SecretInterface {
   return newSecrets(c, namespace)
}

func (c *CoreV1Client) Services(namespace string) ServiceInterface {
   return newServices(c, namespace)
}

func (c *CoreV1Client) ServiceAccounts(namespace string) ServiceAccountInterface {
   return newServiceAccounts(c, namespace)
}

2.5.2 CoreV1Interface

type CoreV1Interface interface {
   RESTClient() rest.Interface
   ComponentStatusesGetter
   ConfigMapsGetter
   EndpointsGetter
   EventsGetter
   LimitRangesGetter
   NamespacesGetter
   NodesGetter
   PersistentVolumesGetter
   PersistentVolumeClaimsGetter
   PodsGetter
   PodTemplatesGetter
   ReplicationControllersGetter
   ResourceQuotasGetter
   SecretsGetter
   ServicesGetter
   ServiceAccountsGetter
}

CoreV1Interface中包含了各种K8s对象的调用接口,例如PodsGetter是对k8s中pod的增删改查,ServicesGetter是对k8s中的service的增删改查。

2.5.3 PodsGetter

以PodsGetter为例分析CoreV1Client对pod对象的增删改查。 之前的实例代码如下:

pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})

CoreV1().Pods()

func (c *CoreV1Client) Pods(namespace string) PodInterface {
	return newPods(c, namespace)
}

newPods

// newPods returns a Pods
func newPods(c *CoreV1Client, namespace string) *pods {
	return &pods{
		client: c.RESTClient(),
		ns:     namespace,
	}
}

CoreV1().Pods()的方法实际是调用了newPods方法,创建pods对象,pods对象继承了rest.Interface接口,即最终的实现本质是RESTClient的HTTP调用

// pods implements PodInterface
type pods struct {
   client rest.Interface
   ns     string
}

pods对象实现了PodInterface接口。PodInterface定义了pods对象的增删改查。

PodInterface

type PodInterface interface {
   Create(ctx context.Context, pod *v1.Pod, opts metav1.CreateOptions) (*v1.Pod, error)
   Update(ctx context.Context, pod *v1.Pod, opts metav1.UpdateOptions) (*v1.Pod, error)
   UpdateStatus(ctx context.Context, pod *v1.Pod, opts metav1.UpdateOptions) (*v1.Pod, error)
   Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
   DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
   Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Pod, error)
   List(ctx context.Context, opts metav1.ListOptions) (*v1.PodList, error)
   Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
   Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Pod, err error)
   Apply(ctx context.Context, pod *corev1.PodApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Pod, err error)
   ApplyStatus(ctx context.Context, pod *corev1.PodApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Pod, err error)
   UpdateEphemeralContainers(ctx context.Context, podName string, pod *v1.Pod, opts metav1.UpdateOptions) (*v1.Pod, error)

   PodExpansion
}

PodsGetter

type PodsGetter interface {
   Pods(namespace string) PodInterface
}

PodsGetter继承了PodInterface的接口。

Pods().List()

// List takes label and field selectors, and returns the list of Pods that match those selectors.
func (c *pods) List(ctx context.Context, opts metav1.ListOptions) (result *v1.PodList, err error) {
   var timeout time.Duration
   if opts.TimeoutSeconds != nil {
      timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
   }
   result = &v1.PodList{}
   err = c.client.Get().
      Namespace(c.ns).
      Resource("pods").
      VersionedParams(&opts, scheme.ParameterCodec).
      Timeout(timeout).
      Do(ctx).
      Into(result)
   return
}

Pods.List()方法通过RESTClient的HTTP Get调用来实现对k8s的pod的资源获取。

// List takes label and field selectors, and returns the list of Pods that match those selectors.
func (c *pods) List(ctx context.Context, opts metav1.ListOptions) (result *v1.PodList, err error) {
   var timeout time.Duration
   if opts.TimeoutSeconds != nil {
      timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
   }
   result = &v1.PodList{}
   err = c.client.Get().
      Namespace(c.ns).
      Resource("pods").
      VersionedParams(&opts, scheme.ParameterCodec).
      Timeout(timeout).
      Do(ctx).
      Into(result)
   return
}