歡迎訪問我的GitHub
https://github.com/zq2599/blog_demos
內容:所有原創文章分類匯總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;
系列文章鏈接
- client-go實戰之一:準備作業
- client-go實戰之二:RESTClient
- client-go實戰之三:Clientset
- client-go實戰之四:dynamicClient
- client-go實戰之五:DiscoveryClient
本篇概覽
- 本文是《client-go實戰》系列的第二篇,前文咱們提到過client-go一共有四種客戶端:RESTClient、ClientSet、DynamicClient、DiscoveryClient,而RESTClient是最基礎的版本,其他三種都是基于RESTClient封裝的,今天咱們通過實戰編碼來學習RESTClient,熟悉最基礎的遠程操作步驟;
- 本篇由以下幾部分組成:
- 簡介RESTClient
- 每次編碼前的準備作業
- 正式編碼
- 驗證
- 關鍵原始碼分析
RESTClient簡介
- RESTClient是client-go最基礎的客戶端,主要是對HTTP Reqeust進行了封裝,對外提供RESTful風格的API,并且提供豐富的API用于各種設定,相比其他幾種客戶端雖然更復雜,但是也更為靈活;
- 使用RESTClient對kubernetes的資源進行增刪改查的基本步驟如下:
- 確定要操作的資源型別(例如查找deployment串列),去官方API檔案中找到對于的path、資料結構等資訊,后面會用到;
- 加載配置kubernetes組態檔(和kubectl使用的那種kubeconfig完全相同);
- 根據組態檔生成配置物件,并且通過API對配置物件就行設定(例如請求的path、Group、Version、序列化反序列化工具等);
- 創建RESTClient實體,入參是配置物件;
- 呼叫RESTClient實體的方法向kubernetes的API Server發起請求,編碼用fluent風格將各種引數傳入(例如指定namespace、資源等),如果是查詢類請求,還要傳入資料結構實體的指標,改資料結構用于接受kubernetes回傳的查詢結果;
- 接下來的編碼實戰也是按照上述流程進行的;
實戰內容
- 本次實戰內容很簡單:查詢kube-system這個namespace下的所有pod,然后在控制臺列印每個pod的幾個關鍵欄位;
- 感謝您耐心聽我啰嗦了一大堆,接下來開始實戰吧;
原始碼下載
- 本篇實戰中的原始碼可在GitHub下載到,地址和鏈接資訊如下表所示(https://github.com/zq2599/blog_demos):
| 名稱 | 鏈接 | 備注 |
|---|---|---|
| 專案主頁 | https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 |
| git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協議 |
| git倉庫地址(ssh) | [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協議 |
- 這個git專案中有多個檔案夾,client-go相關的應用在client-go-tutorials檔案夾下,如下圖紅框所示:

- client-go-tutorials檔案夾下有多個子檔案夾,本篇對應的原始碼在restclientdemo目錄下,如下圖紅框所示:

查看官方檔案,獲取編碼所需內容
-
瀏覽器打開官方API檔案,地址:https://v1-19.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/
-
找到pod的API檔案,如下圖,確定了path和namespace引數:

- 然后還要關注回應的資料結構,如下圖紅框,回傳的是:

- 點擊上圖紅框中的內容,可見PodList的詳情,這就是我們編碼時所需的資料結構:

- 掌握了請求和回應的詳細資訊,可以開始編碼了;
編碼
- 新建檔案夾restclientdemo,在里面執行以下命令,新建module:
go mod init restclientdemo
- 添加k8s.io/api和k8s.io/client-go這兩個依賴,注意版本要匹配kubernetes環境:
go get k8s.io/[email protected]
go get k8s.io/[email protected]
- 新建main.go,內容如下,已經都添加了詳細的注釋,就不贅述了:
package main
import (
"context"
"flag"
"fmt"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"path/filepath"
)
func main() {
var kubeconfig *string
// home是家目錄,如果能取得家目錄的值,就可以用來做默認值
if home:=homedir.HomeDir(); home != "" {
// 如果輸入了kubeconfig引數,該引數的值就是kubeconfig檔案的絕對路徑,
// 如果沒有輸入kubeconfig引數,就用默認路徑~/.kube/config
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
// 如果取不到當前用戶的家目錄,就沒辦法設定kubeconfig的默認目錄了,只能從入參中取
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
// 從本機加載kubeconfig組態檔,因此第一個引數為空字串
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
// kubeconfig加載失敗就直接退出了
if err != nil {
panic(err.Error())
}
// 參考path : /api/v1/namespaces/{namespace}/pods
config.APIPath = "api"
// pod的group是空字串
config.GroupVersion = &corev1.SchemeGroupVersion
// 指定序列化工具
config.NegotiatedSerializer = scheme.Codecs
// 根據配置資訊構建restClient實體
restClient, err := rest.RESTClientFor(config)
if err!=nil {
panic(err.Error())
}
// 保存pod結果的資料結構實體
result := &corev1.PodList{}
// 指定namespace
namespace := "kube-system"
// 設定請求引數,然后發起請求
// GET請求
err = restClient.Get().
// 指定namespace,參考path : /api/v1/namespaces/{namespace}/pods
Namespace(namespace).
// 查找多個pod,參考path : /api/v1/namespaces/{namespace}/pods
Resource("pods").
// 指定大小限制和序列化工具
VersionedParams(&metav1.ListOptions{Limit:100}, scheme.ParameterCodec).
// 請求
Do(context.TODO()).
// 結果存入result
Into(result)
if err != nil {
panic(err.Error())
}
// 表頭
fmt.Printf("namespace\t status\t\t name\n")
// 每個pod都列印namespace、status.Phase、name三個欄位
for _, d := range result.Items {
fmt.Printf("%v\t %v\t %v\n",
d.Namespace,
d.Status.Phase,
d.Name)
}
}
- 編碼完成,執行go run main.go,即可獲取指定namespace下所有pod的資訊,控制臺輸出如下:
(base) zhaoqindeMBP:restclientdemo zhaoqin$ go run main.go
namespace status name
kube-system Running coredns-7f89b7bc75-5pdwc
kube-system Running coredns-7f89b7bc75-nvbvm
kube-system Running etcd-hedy
kube-system Running kube-apiserver-hedy
kube-system Running kube-controller-manager-hedy
kube-system Running kube-flannel-ds-v84vc
kube-system Running kube-proxy-hlppx
kube-system Running kube-scheduler-hedy
- 至此,RESTClient客戶端從編碼到驗證都完成了;
如何將收到的資料反序列化為PodList物件?
- 前面的代碼比較簡單,但是有一處引起了我的興趣,如下圖紅框所示,result是corev1.PodList型別的結構體指標,restClient收到kubernetes回傳的資料后,如何知道要將資料反序列化成corev1.PodList型別呢(Into方法入參型別為runtime.Object)?

- 之前的代碼中有一行設定了編解碼工具:config.NegotiatedSerializer = scheme.Codecs,展開這個scheme.Codecs,可見設定的時候確定了序列化工具為runtime.Serializer:

- Serializer的typer欄位型別是runtime.ObjectTyper,這里實際上是runtime.Scheme,因此ObjectTyper.ObjectKinds方法,實際上就是Scheme.ObjectKinds方法,在里面根據s.typeToGVK[t]拿到了GVK,也就是v1.PodList:

- 有了這個GVK就確定的回傳資料的型別,最終呼叫caseSensitiveJSONIterator.Unmarshal(data, obj)完成byte陣列到物件的反序列化操作:

- 最后還有一行關鍵代碼,將data的內容寫到最外層的Into方法的入參中:

- 原始碼分析完成,簡單來說除了利用反射獲取實際型別,還有就是Scheme內部維護的資料型別和GVK的關系映射表;
- 至此,RESTClient的實戰就完成了,希望本篇能幫助您打好基礎,這樣后面在體驗其他三種客戶端時已對其底層的實作原理了然于胸;
你不孤單,欣宸原創一路相伴
- Java系列
- Spring系列
- Docker系列
- kubernetes系列
- 資料庫+中間件系列
- DevOps系列
你不孤單,欣宸原創一路相伴
- Java系列
- Spring系列
- Docker系列
- kubernetes系列
- 資料庫+中間件系列
- DevOps系列
歡迎關注公眾號:程式員欣宸
微信搜索「程式員欣宸」,我是欣宸,期待與您一同暢游Java世界...
https://github.com/zq2599/blog_demos
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/298208.html
標籤:其他
