client-go源码目录结构说明
| 源码目录 | 说明 |
|---|---|
| discovery | 提供DiscoveryClient发现客户端 |
| dynamic | 提供DynamicClient动态客户端 |
| informers | 每种Kubernetes资源的informer实现 |
| kubernetes | 提供ClientSet客户端 |
| listers | 为每一个Kubernetes资源提供Lister功能, 该功能对Get和List请求提供只读的缓存数据 |
| plugin | 提供OpenStack、GCP和Azure等云服务商授权插件 |
| rest | 提供RESTClient客户端, 对Kubernetes API Server执行RESTful操作 |
| scale | 提供ScaleClient客户端, 用于扩容或缩容Deployment、ReplicaSet、Replication Controller等资源对象 |
| tools | 提供常用工具, 例如SharedInformer、Reflector、DeltaFIFO及Indexers. 提供Client查询和缓存机制, 以减少向kube-apiserver发起的请求数等 |
| transport | 提供安全的TCP连接, 支持Http Stream, 某些操作需要再客户端及容器之间传输二进制流, 例如exec、attach等操作. 该功能由内部的spdy包提供支持 |
| util | 提供常用方法, 例如WorkQueue工作队列、Certificate证书管理等 |
Client客户端对象
client-go支持4种Client客户端对象与Kubernetes API Server交互的方式
RESTClient
RESTClient是最基础的客户端. RESTClient对HTTP Request进行了封装, 实现了RESTful风格的API. ClientSet、DynamicClient及DiscoveryClient客户端都是基于RESTClient实现的.
ClientSet
ClientSet再RESTClient的基础上封装了对Resource和Version的管理方法. 每一个Resource可以理解为一个客户端, 而ClientSet则是多个客户端的集合, 每一个Resource和Version都以函数的方式暴露给开发者. ClientSet只能够处理Kubernetes内置资源, 它是通过client-gen代码生成器自动生成的
DynamicClient
DynamicClient与ClientSet最大的不同之处是, ClientSet仅仅能访问Kubernetes机自带的资源(即Client集合内的资源), 不能直接访问CRD自定义资源. DynamicClient能够处理Kubernetes中的所有资源对象, 包括Kubernetes内置资源与CRD自定义资源.
DiscoveryClient
DiscoveryClient发现客户端, 用于发现kube-apiserver所支持的资源组、资源版本、资源信息(即Group、Versions、Resources).
示例
示例1 获取集群所有node
package main
import (
"fmt"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/kubernetes/scheme"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("","/Users/sundongmin/.kube/config")
if err != nil {
panic(err.Error())
}
config.APIPath = "api"
config.GroupVersion = &corev1.SchemeGroupVersion
config.NegotiatedSerializer = scheme.Codecs
restClient, err := rest.RESTClientFor(config)
if err != nil {
panic(err.Error())
}
result := &corev1.NodeList{}
err = restClient.Get().Namespace("").Resource("nodes").VersionedParams(&metav1.ListOptions{Limit: 100}, scheme.ParameterCodec).Do().Into(result)
if err != nil {
panic(err)
}
for _, d := range result.Items {
fmt.Printf("Node Name %v \n", d.Name)
}
}
示例2 对某个namespace创建configmap
package main
import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
"log"
"time"
)
const CONFIGMAP_NAME = "simon-test-configmap"
func createConfigmap(namespace string, clientset *kubernetes.Clientset) error {
configmapClient := clientset.CoreV1().ConfigMaps(namespace)
_, err := configmapClient.Get(CONFIGMAP_NAME, v1.GetOptions{})
if errors.IsNotFound(err) {
configmapObj := &apiv1.ConfigMap{
TypeMeta: v1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: v1.ObjectMeta{
Name: CONFIGMAP_NAME,
},
Data: map[string]string{
"test": "test",
},
}
_, err := configmapClient.Create(configmapObj)
if err != nil {
return err
} else {
log.Println("create configmap success")
return nil
}
}
return nil
}
func main() {
config, err := clientcmd.BuildConfigFromFlags("","/Users/sundongmin/.kube/config")
if err != nil {
panic(err.Error())
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
stopCh := make(chan struct{})
defer close(stopCh)
shareInformers := informers.NewSharedInformerFactory(clientset, time.Second)
informer := shareInformers.Core().V1().Namespaces().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func (obj interface{}) {
nObj := obj.(v1.Object)
log.Printf("New namespaces add %s", nObj.GetName())
if nObj.GetName() == "citest" {
err := createConfigmap(nObj.GetName(), clientset)
if err != nil {
log.Println("create configmap fail, fail at %s", err)
}
}
},
})
informer.Run(stopCh)
}
参考资料
郑东旭-Kubernetes源码剖析