簡介:雲原生社區活動---Kubernetes源碼剖析第一期
有幸參與雲原生社區舉辦的Kubernetes源碼剖析活動,活動主要以書籍《Kubernetes源碼剖析》爲主要思路進行展開,提出在看書過程當中遇到的問題,和社區成員一塊兒討論,最後會將結果總結到雲原生社區的知識星球或Github。node
第一期活動主要以書本第五章<Client-go編程式交互>爲主題進行學習,計劃共三週半。git
計劃以下:github
學習總得有個重要的優先級,我我的的優先級是這樣的,僅供參考:編程
學習環境相關:api
本文主題緩存
本文是第一週,課題有兩個:app
Client-go源碼目錄結構框架
[root@normal11 k8s-client-go]# tree . -L 1
.
├── CHANGELOG.md
├── code-of-conduct.md
├── CONTRIBUTING.md
├── discovery
├── dynamic
├── examples
├── Godeps
├── go.mod
├── go.sum
├── informers
├── INSTALL.md
├── kubernetes
├── kubernetes_test
├── LICENSE
├── listers
├── metadata
├── OWNERS
├── pkg
├── plugin
├── README.md
├── rest
├── restmapper
├── scale
├── SECURITY_CONTACTS
├── testing
├── third_party
├── tools
├── transport
└── util 學習
client-go代碼庫已經集成到了Kubernetes源碼中,因此書本中展現的內容是在Kubernetes源碼中源碼結構,而這裏展現的是Client-go代碼庫中原始的內容,因此多了一些源碼以外的內容,例如README、example、go.mod等。下面講一下各個目錄的做用,內容引自書本:測試
幾種Client-go客戶端
下圖是一個簡單的總結,其中ClientSet、DynamicClient、DiscoveryClient都是基於RESTClient封裝的。
RESTClient
最基礎的客戶端,對HTTP Request進行了封裝,實現了RESTFul風格的API。
案例代碼:
package main
import (
"fmt" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("", "/root/.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) }
}
預期運行結果將會打印K8S集羣中的node
ClientSet
對RESTClient進行了對象分類方式的封裝,能夠實例化特定資源的客戶端,
以Resource和Version的方式暴露。例如實例化一個只操做appsv1版本的Deploy客戶端,
ClientSet能夠認爲是一系列資源的集合客戶端。缺點是不能直接訪問CRD。
經過client-gen代碼生成器生成帶有CRD資源的ClientSet後能夠訪問CRD資源。(未測試)
案例代碼:
package main
import (
apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("", "/root/.kube/config") if err != nil { panic(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } podClient := clientset.CoreV1().Pods(apiv1.NamespaceDefault) list, err := podClient.List(metav1.ListOptions{Limit: 500}) if err != nil { panic(err) } for _, d := range list.Items { if d.Name == "" { } // fmt.Printf("NAME:%v t NAME:%v t STATUS: %+vn ", d.Namespace, d.Name, d.Status) } //請求namespace爲default下的deploy deploymentClient := clientset.AppsV1().Deployments(apiv1.NamespaceDefault) deployList, err2 := deploymentClient.List(metav1.ListOptions{Limit: 500}) if err2 != nil { panic(err2) } for _, d := range deployList.Items { if d.Name == "" { } // fmt.Printf("NAME:%v t NAME:%v t STATUS: %+vn ", d.Namespace, d.Name, d.Status) } // 請求ds資源 todo 有興趣能夠嘗試下 // clientset.AppsV1().DaemonSets()
}
代碼中分別打印了獲取到K8S集羣中的500個Pod和500個deploy,目前打印語句是註釋了,若是要看效果須要先刪掉註釋。
案例代碼中還留了一個小內容,請求獲取daemonset資源,感興趣的能夠試一試。
DynamicClient
這是一種動態客戶端,對K8S任意資源進行操做,包括CRD。
請求返回的結果是map[string]interface{}
代碼案例:
package main
import (
"fmt" apiv1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "k8s.io/client-go/tools/clientcmd"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("", "/root/.kube/config") if err != nil { panic(err) } dymaicClient, err := dynamic.NewForConfig(config) checkErr(err) //map[string]interface{} //TODO 獲取CRD資源 這裏是獲取了TIDB的CRD資源 // gvr := schema.GroupVersionResource{Version: "v1alpha1", Resource: "tidbclusters", Group: "pingcap.com"} // unstructObj, err := dymaicClient.Resource(gvr).Namespace("tidb-cluster").List(metav1.ListOptions{Limit: 500}) // checkErr(err) // fmt.Println(unstructObj) gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"} unstructObj, err := dymaicClient.Resource(gvr).Namespace(apiv1.NamespaceDefault).List(metav1.ListOptions{Limit: 500}) checkErr(err) // fmt.Println(unstructObj) podList := &corev1.PodList{} err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.UnstructuredContent(), podList) checkErr(err) for _, d := range podList.Items { fmt.Printf("NAME:%v t NAME:%v t STATUS: %+vn ", d.Namespace, d.Name, d.Status) }
}
func checkErr(err error) {
if err != nil { panic(err) }
}
這個案例是打印了namespace爲default下的500個pod,一樣的,在案例中也有一個todo,獲取CRD資源,感興趣的能夠嘗試一下。若是K8S集羣中沒有TIDB的資源能夠自行換成本身想要的CRD資源。
代碼中已經有獲取v1alpha1版本的tidbclusters資源。若是你不知道CRD相關的信息,能夠按照下面的步驟來找出對應的信息:
這樣 資源的GVR(Group、Version、Resource)都有了
DiscoveryClient
這是一種發現客戶端,在前面的客戶端中須要知道資源的Resource和Version才能找到你想要的,
這些信息太多很難所有記住,這個客戶端用於獲取資源組、版本等信息。
前面用到的api-resources和api-versions都是經過discoveryClient客戶端實現的, 源碼在Kubernetes源碼庫中 pkg/kubectl/cmd/apiresources/apiresources.go pkg/kubectl/cmd/apiresources/apiversions.go
// RunAPIResources does the work
func (o APIResourceOptions) RunAPIResources(cmd cobra.Command, f cmdutil.Factory) error {
w := printers.GetNewTabWriter(o.Out) defer w.Flush() //拿到一個DiscoveryClient客戶端 discoveryclient, err := f.ToDiscoveryClient() if err != nil { return err }
// RunAPIVersions does the work
func (o *APIVersionsOptions) RunAPIVersions() error {
// Always request fresh data from the server o.discoveryClient.Invalidate() //經過discoveryClient獲取group相關信息 groupList, err := o.discoveryClient.ServerGroups() if err != nil { return fmt.Errorf("couldn't get available api versions from server: %v", err) }
案例代碼:
獲取集羣中的GVR
package main
import (
"fmt" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery" "k8s.io/client-go/tools/clientcmd"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("","/root/.kube/config") if err != nil { panic(err.Error()) } discoveryClient, err := discovery.NewDiscoveryClientForConfig(config) if err != nil { panic(err.Error()) } _, APIResourceList, err := discoveryClient.ServerGroupsAndResources() if err != nil { panic(err.Error()) } for _, list := range APIResourceList { gv, err := schema.ParseGroupVersion(list.GroupVersion) if err != nil { panic(err.Error()) } for _, resource := range list.APIResources { fmt.Printf("name: %v, group: %v, version %vn", resource.Name, gv.Group, gv.Version) } }
}
預期效果:打印集羣中的GVR
[root@normal11 discoveryclient]# go run main.go name: bindings, group: , version v1 name: componentstatuses, group: , version v1 name: configmaps, group: , version v1 name: endpoints, group: , version v1 ...
DiscoveryClient在請求到數據以後會緩存到本地,默認存儲位置是~/.kube/cache和~/.kube/http-cache,默認是每10分鐘會和API Server同步一次。
總結
第一週主要是瞭解下各類客戶端的使用以及不一樣,有時間的能夠再進行一些拓展試驗,研究對象能夠選擇一些主流的框架或官方示例,例如:
延伸閱讀:
始發於 四顆咖啡豆,轉載請聲明出處. 關注公糉號->[四顆咖啡豆] 獲取最新內容