显然,dynamicClient还需要用户自己设置resource资源。其实更多的时候用户只是希望如果要操作pod,那么生成一个podClient;如果要操作service,那么 生成一个serviceClient。ClientSet就是满足用户的这种需要。
ClientSet
ClientSet是多个Client的集合,定义在/pkg/client/clientset_generated/release_1_5/clientset.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| type Clientset struct { *discovery.DiscoveryClient *v1core.CoreV1Client *v1beta1apps.AppsV1beta1Client *v1beta1authentication.AuthenticationV1beta1Client *v1beta1authorization.AuthorizationV1beta1Client *v1autoscaling.AutoscalingV1Client *v1batch.BatchV1Client *v2alpha1batch.BatchV2alpha1Client *v1alpha1certificates.CertificatesV1alpha1Client *v1beta1extensions.ExtensionsV1beta1Client *v1beta1policy.PolicyV1beta1Client *v1alpha1rbac.RbacV1alpha1Client *v1beta1storage.StorageV1beta1Client }
|
可以看到ClientSet是按包来组织Client的。
再来看下ClientSet的生成函数。NewForConfig()可以生成一个ClientSet。可以看出,在NewForConfig()中调用了各子client的生成函数,如CoreV1Client通过v1core.NewForConfig(&configShallowCopy)生成,后面的文章将以CoreV1Client为例展示ClientSet的各种操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| func NewForConfig(c *restclient.Config) (*Clientset, error) { configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) } var clientset Clientset var err error clientset.CoreV1Client, err = v1core.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.AppsV1beta1Client, err = v1beta1apps.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.AuthenticationV1beta1Client, err = v1beta1authentication.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.AuthorizationV1beta1Client, err = v1beta1authorization.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.AutoscalingV1Client, err = v1autoscaling.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.BatchV1Client, err = v1batch.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.BatchV2alpha1Client, err = v2alpha1batch.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.CertificatesV1alpha1Client, err = v1alpha1certificates.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.ExtensionsV1beta1Client, err = v1beta1extensions.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.PolicyV1beta1Client, err = v1beta1policy.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.RbacV1alpha1Client, err = v1alpha1rbac.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.StorageV1beta1Client, err = v1beta1storage.NewForConfig(&configShallowCopy) if err != nil { return nil, err } clientset.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) if err != nil { glog.Errorf("failed to create the DiscoveryClient: %v", err) return nil, err } return &clientset, nil }
|
ClientSet可以通过Core()方法获取CoreV1Client:
1 2 3 4 5 6 7
| func (c *Clientset) Core() v1core.CoreV1Interface { if c == nil { return nil } return c.CoreV1Client }
|
CoreV1Client
CoreV1Client定义在/pkg/client/clientset_generated/release_1_5/typed/core/v1/core_client.go中,可以通过NewForConfig()返回一个CoreV1Client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type CoreV1Client struct { restClient restclient.Interface } func NewForConfig(c *restclient.Config) (*CoreV1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } client, err := restclient.RESTClientFor(&config) if err != nil { return nil, err } return &CoreV1Client{client}, nil }
|
NewForConfig()先通过setConfigDefaults()设置config,然后调用restclient.RESTClientFor()生成RESTClient,最后把RESTClient封装成CoreV1Client并返回。
setConfigDefaults()定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func setConfigDefaults(config *restclient.Config) error { gv, err := unversioned.ParseGroupVersion("/v1") if err != nil { return err } if !registered.IsEnabledVersion(gv) { return fmt.Errorf("/v1 is not enabled") } config.APIPath = "/api" if config.UserAgent == "" { config.UserAgent = restclient.DefaultKubernetesUserAgent() } copyGroupVersion := gv config.GroupVersion = ©GroupVersion config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs} return nil }
|
可以看出,setConfigDefaults()把config的APIPath字段设置为”/api”,GroupVersion字段设置为对应的gv。
CoreV1Client定义有Nodes(),Pods(),PersistentVolumes()等方法,以Pods()为例:
1 2 3
| func (c *CoreV1Client) Pods(namespace string) PodInterface { return newPods(c, namespace) }
|
可以看到Pods中调用了newPods(c, namespace)生成一个pods,pods可以对”pods”资源进行各种操作。
pods
pods定义在/pkg/client/clientset_generated/release_1_5/typed/core/v1/pod.go中:
1 2 3 4 5 6 7 8 9 10 11 12 13
| type pods struct { client restclient.Interface ns string } func newPods(c *CoreV1Client, namespace string) *pods { return &pods{ client: c.RESTClient(), ns: namespace, } }
|
可以看到pods包含一个RESTClient和ns(即namespace)。
再来看下pods的成员方法,这些成员方法都调用了RESTClient:
Create()
1 2 3 4 5 6 7 8 9 10 11
| func (c *pods) Create(pod *v1.Pod) (result *v1.Pod, err error) { result = &v1.Pod{} err = c.client.Post(). Namespace(c.ns). Resource("pods"). Body(pod). Do(). Into(result) return }
|
Update()
1 2 3 4 5 6 7 8 9 10 11 12
| func (c *pods) Update(pod *v1.Pod) (result *v1.Pod, err error) { result = &v1.Pod{} err = c.client.Put(). Namespace(c.ns). Resource("pods"). Name(pod.Name). Body(pod). Do(). Into(result) return }
|
Delete()
1 2 3 4 5 6 7 8 9 10
| func (c *pods) Delete(name string, options *v1.DeleteOptions) error { return c.client.Delete(). Namespace(c.ns). Resource("pods"). Name(name). Body(options). Do(). Error() }
|
Get()
1 2 3 4 5 6 7 8 9 10 11
| func (c *pods) Get(name string) (result *v1.Pod, err error) { result = &v1.Pod{} err = c.client.Get(). Namespace(c.ns). Resource("pods"). Name(name). Do(). Into(result) return }
|
List()
1 2 3 4 5 6 7 8 9 10 11
| func (c *pods) List(opts v1.ListOptions) (result *v1.PodList, err error) { result = &v1.PodList{} err = c.client.Get(). Namespace(c.ns). Resource("pods"). VersionedParams(&opts, api.ParameterCodec). Do(). Into(result) return }
|
Watch()
1 2 3 4 5 6 7 8 9
| func (c *pods) Watch(opts v1.ListOptions) (watch.Interface, error) { return c.client.Get(). Prefix("watch"). Namespace(c.ns). Resource("pods"). VersionedParams(&opts, api.ParameterCodec). Watch() }
|
Patch()
1 2 3 4 5 6 7 8 9 10 11 12 13
| func (c *pods) Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *v1.Pod, err error) { result = &v1.Pod{} err = c.client.Patch(pt). Namespace(c.ns). Resource("pods"). SubResource(subresources...). Name(name). Body(data). Do(). Into(result) return }
|
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package main import ( "flag" "fmt" apiv1 "k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" ) func main() { kubeconfig := flag.String("kubeconfig", "/root/.kube/config", "Path to a kube config. Only required if out-of-cluster.") fmt.Println(kubeconfig) flag.Parse() config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) if err != nil { fmt.Println("error") } clientset, err := kubernetes.NewForConfig(config) if err != nil { fmt.Println("error") } podClient := clientset.Core().Pods("") pods, err := podClient.List(apiv1.ListOptions{}) if err != nil { fmt.Println("error") } for _, pod := range pods.Items { fmt.Println(pod) } }
|