k8s client-go 源码分析(二)

843 阅读3分钟

紧接k8s client-go 源码分析(一)

2.6 RestClient

RESTClient对象的创建同样是以来传入的config信息。

client, err := rest.RESTClientForConfigAndClient(&config, h)

2.6.1 RESTClientForConfigAndClient

// RESTClientForConfigAndClient returns a RESTClient that satisfies the requested attributes on a
// client Config object.
// Unlike RESTClientFor, RESTClientForConfigAndClient allows to pass an http.Client that is shared
// between all the API Groups and Versions.
// Note that the http client takes precedence over the transport values configured.
// The http client defaults to the `http.DefaultClient` if nil.
func RESTClientForConfigAndClient(config *Config, httpClient *http.Client) (*RESTClient, error) {
   if config.GroupVersion == nil {
      return nil, fmt.Errorf("GroupVersion is required when initializing a RESTClient")
   }
   if config.NegotiatedSerializer == nil {
      return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient")
   }

   baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
   if err != nil {
      return nil, err
   }

   rateLimiter := config.RateLimiter
   if rateLimiter == nil {
      qps := config.QPS
      if config.QPS == 0.0 {
         qps = DefaultQPS
      }
      burst := config.Burst
      if config.Burst == 0 {
         burst = DefaultBurst
      }
      if qps > 0 {
         rateLimiter = flowcontrol.NewTokenBucketRateLimiter(qps, burst)
      }
   }

   var gv schema.GroupVersion
   if config.GroupVersion != nil {
      gv = *config.GroupVersion
   }
   clientContent := ClientContentConfig{
      AcceptContentTypes: config.AcceptContentTypes,
      ContentType:        config.ContentType,
      GroupVersion:       gv,
      Negotiator:         runtime.NewClientNegotiator(config.NegotiatedSerializer, gv),
   }

   restClient, err := NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient)
   if err == nil && config.WarningHandler != nil {
      restClient.warningHandler = config.WarningHandler
   }
   return restClient, err
}

RESTClientForConfigAndClient中调用NewRESTClient创建RESTClient

2.6.2 NewRESTClient

// NewRESTClient creates a new RESTClient. This client performs generic REST functions
// such as Get, Put, Post, and Delete on specified paths.
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientContentConfig, rateLimiter flowcontrol.RateLimiter, client *http.Client) (*RESTClient, error) {
   if len(config.ContentType) == 0 {
      config.ContentType = "application/json"
   }

   base := *baseURL
   if !strings.HasSuffix(base.Path, "/") {
      base.Path += "/"
   }
   base.RawQuery = ""
   base.Fragment = ""

   return &RESTClient{
      base:             &base,
      versionedAPIPath: versionedAPIPath,
      content:          config,
      createBackoffMgr: readExpBackoffConfig,
      rateLimiter:      rateLimiter,

      Client: client,
   }, nil
}

2.6.3 RESTClient结构体

RESTClient是整个clientset的核心数据,RESTClient结构体中包含了http.Client,即本质上RESTClient就是一个http.Client的封装实现。

// RESTClient imposes common Kubernetes API conventions on a set of resource paths.
// The baseURL is expected to point to an HTTP or HTTPS path that is the parent
// of one or more resources.  The server should return a decodable API resource
// object, or an api.Status object which contains information about the reason for
// any failure.
//
// Most consumers should use client.New() to get a Kubernetes API client.
type RESTClient struct {
   // base is the root URL for all invocations of the client
   base *url.URL
   // versionedAPIPath is a path segment connecting the base URL to the resource root
   versionedAPIPath string

   // content describes how a RESTClient encodes and decodes responses.
   content ClientContentConfig

   // creates BackoffManager that is passed to requests.
   createBackoffMgr func() BackoffManager

   // rateLimiter is shared among all requests created by this client unless specifically
   // overridden.
   rateLimiter flowcontrol.RateLimiter

   // warningHandler is shared among all requests created by this client.
   // If not set, defaultWarningHandler is used.
   warningHandler WarningHandler

   // Set specific behavior of the client.  If not set http.DefaultClient will be used.
   Client *http.Client
}

2.6.4 RESTClient.Interface接口

// Interface captures the set of operations for generically interacting with Kubernetes REST apis.
type Interface interface {
   GetRateLimiter() flowcontrol.RateLimiter
   Verb(verb string) *Request
   Post() *Request
   Put() *Request
   Patch(pt types.PatchType) *Request
   Get() *Request
   Delete() *Request
   APIVersion() schema.GroupVersion
}

RESTClient.Interface中Post、Put、Get、Delete时,实际上调用Verb(verb string)函数

// Verb sets the verb this request will use.
func (r *Request) Verb(verb string) *Request {
   r.verb = verb
   return r
}

以List为例

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
}

Verb函数返回一个填充verb字段的Request, 最后调用Do()方法实现一个http请求获取Result。

2.7 总结

client-go对k8s资源对象的调用,先获取k8s的配置信息,链接对配置上节点的apiserver。

整个调用过程如下: kubeconfig -> rest.config -> clientset -> 具体的client(CoreV1Client)->具体资源对象(pod)->RESTClient -> http.Client -> HTTP请求的发送即响应。 clientset中不同的client和client中不同的资源对象方法实现对k8s资源对象的增删改查,常见的client有CoreV1Client、AppV1beta1Client等。

3. client-go对k8s资源的调用

创建clientset

//获取kubeconfig
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
//创建config
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
//创建clientset
clientset, err := kubernetes.NewForConfig(config)
//具体的资源调用见以下例子

3.1 deployment

//声明deployment对象\
var deployment *v1beta1.Deployment\
//构造deployment对象\
//创建deployment\
deployment, err := clientset.AppsV1beta1().Deployments(<namespace>).Create(<deployment>)\
//更新deployment\
deployment, err := clientset.AppsV1beta1().Deployments(<namespace>).Update(<deployment>)\
//删除deployment\
err := clientset.AppsV1beta1().Deployments(<namespace>).Delete(<deployment.Name>, &meta_v1.DeleteOptions{})\
//查询deployment\
deployment, err := clientset.AppsV1beta1().Deployments(<namespace>).Get(<deployment.Name>, &meta_v1.GetOptions{})\
//列出deployment\
deploymentList, err := clientset.AppsV1beta1().Deployments(<namespace>).List(&meta_v1.ListOptions{})\
//watch deployment\
watchInterface, err := clientset.AppsV1beta1().Deployments(<namespace>).Watch(&meta_v1.ListOptions{})\

3.2 service

//声明service对象
var service *v1.Service
//构造service对象
//创建service
service, err := clientset.CoreV1().Services(<namespace>).Create(<service>)
//更新service
service, err := clientset.CoreV1().Services(<namespace>).Update(<service>)
//删除service
err := clientset.CoreV1().Services(<namespace>).Delete(<service.Name>, &meta_v1.DeleteOptions{})
//查询service
service, err := clientset.CoreV1().Services(<namespace>).Get(<service.Name>, &meta_v1.GetOptions{})
//列出service
serviceList, err := clientset.CoreV1().Services(<namespace>).List(&meta_v1.ListOptions{})
//watch service
watchInterface, err := clientset.CoreV1().Services(<namespace>).Watch(&meta_v1.ListOptions{})

4. client-go所用到的设计模式(后续补充)

4.1 建造者模式

type Request struct {
   c *RESTClient

   warningHandler WarningHandler

   rateLimiter flowcontrol.RateLimiter
   backoff     BackoffManager
   timeout     time.Duration

   // generic components accessible via method setters
   verb       string
   pathPrefix string
   subpath    string
   params     url.Values
   headers    http.Header

   // structural elements of the request that are part of the Kubernetes API conventions
   namespace    string
   namespaceSet bool
   resource     string
   resourceName string
   subresource  string

   // output
   err   error
   body  io.Reader
   retry WithRetry
}
// 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
}

4.1 抽象工厂模式