client-go獲取k8s叢集內部連線,實現deployment的增刪改查
一開始寫了一個client-java版本的,但是java放在k8s叢集上跑需要裝jvm而且java的包比較大,client-go版本更適合主機端,下面是整個實現
說明:k8s官方維護的客戶端庫只有go和python版本,所以為了穩定性建議使用這兩個版本,考慮到k8s是go實現的,我這裡也就選擇go版本。至於客戶端連線k8s叢集,在具體的生產環境中不建議外部連線訪問。原因一是生產環境中的k8s配置檔案重要,一般如果對接其他公司的業務,雖然有鑑權,人家也不願意把配置檔案拷貝給你,因為有了叢集的配置檔案,外部的這個專案的許可權就很大,相當於給叢集開了一個隱患口子,要知道k8s叢集中有可能是該公司的整個業務。原因二叢集內部訪問不需要那麼複雜的鑑權,反而更省事點,只需要寫個小應用部署到k8s叢集中即可。應用已經在叢集內部了,就沒有鑑權的概念了,其他三方服務只需要呼叫小應用的api即可操作k8s。
1. 構建goWeb小應用匯入依賴:
a. 不管是走go的代理還是其他辦法,這裡預設能搭建goWeb專案,並且能夠使用go mod tidy拉取包。
b. 按照官方文件匯入依賴這裡我用的是0.17.0版本,此處有坑,不僅僅這個版本有這個坑,其他版本很有可能也有,完全正常的匯入但是會存在jar包之間版本不一致問題,這個問題會導致go build無法構建,是官方自身的相容問題,報錯資訊為:
# k8s.io/client-go/rest
../../../../goworkspace/pkg/mod/k8s.io/[email protected]+incompatible/rest/request.go:598:31: not enough arguments in call to watch.NewStreamWatcher
have (*versioned.Decoder)
want (watch.Decoder, watch.Reporter)
c. 可以嘗試手動替換k8s.io/[email protected]為k8s.io/[email protected]來解決。在終端執行# go mod download -json k8s.io/[email protected]最終gomod的關於k8s的所有依賴檔案如下所示:
1 require ( 2 k8s.io/api v0.17.0 // indirect 3 k8s.io/apimachinery v0.17.0 4 k8s.io/client-go v11.0.0+incompatible 5 k8s.io/utils v0.0.0-20191114184206-e782cd3c129f // indirect 6 sigs.k8s.io/yaml v1.1.0 // indirect 7 ) 8 9 replace ( 10 k8s.io/api => k8s.io/api v0.0.0-20191004102349-159aefb8556b 11 k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20191004105649-b14e3c49469a 12 k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20191004074956-c5d2f014d689 13 sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.3.0 14 )
這裡參考部落格為:https://segmentfault.com/a/1190000021077653?utm_source=tag-newest
最終go build就沒問題了。
2. 配置叢集內部訪問的客戶端
a. 內部訪問k8s客戶端使用defaultClient即可,但是這裡第二個坑,client-go裡面預設的客戶端尋找的是~/.kube下的config檔案,並且需要叢集的ip和port,也就是說需要人為的去配置環境變數以便滿足ip和port的寫入需要,需要提前把config放到~/.kube下。恰巧客戶的環境也沒配置環境變數,也沒把config拷到響應的目錄下,只能找其他辦法。由於之前寫過一個java的客戶端呼叫,裡面的defaultClient是可以訪問到的。所以看下java中的尋找路徑,發現了一個上下文路徑的東西。最終改造client-go客戶端資訊如下:
1 package utils 2 3 import ( 4 "k8s.io/client-go/kubernetes" 5 "k8s.io/client-go/tools/clientcmd" 6 "log" 7 "os" 8 "path/filepath" 9 ) 10 11 // 獲取叢集內部k8s客戶端 12 func K8sClient() *kubernetes.Clientset { 13 // 使用當前上下文環境 14 kubeconfig := filepath.Join( 15 os.Getenv("KUBECONFIG"), 16 ) 17 config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) 18 if err != nil { 19 log.Fatal(err) 20 } 21 // 根據指定的 config 建立一個新的 clientSet 22 clientSet, err := kubernetes.NewForConfig(config) 23 if err != nil { 24 panic(err.Error()) 25 } 26 return clientSet 27 }
其中os.Getenv就是拿k8s的預設配置檔案,只要該應用部署在k8s叢集環境中,這個客戶端就可以正確返回和使用。
3. pod列表,deployment列表,deployment擴縮容等實現
1 // 拿客戶端 2 clientSet := utils.K8sClient() 3 //獲取PODS列表,不傳namespace預設查全部 4 pods, err := clientSet.CoreV1().Pods(nameSpace).List(metav1.ListOptions{}) 5 if err != nil { 6 log.Println(err.Error()) 7 } 8 // deployment列表獲取 9 deploymentsClient := clientSet.AppsV1().Deployments(nameSpace) 10 deployments, err := deploymentsClient.List(metav1.ListOptions{}) 11 if err != nil { 12 panic(err) 13 } 14 // deployment詳情獲取 15 deploymentsClient := clientSet.AppsV1().Deployments(nameSpace) 16 deployment, err := deploymentsClient.Get(deploymentName, metav1.GetOptions{}) 17 if err != nil { 18 panic(err) 19 } 20 // 擴縮容,num是擴縮容至多少 21 deploymentsClient := clientSet.AppsV1().Deployments(nameSpace) 22 retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { 23 result, getErr := deploymentsClient.Get(deploymentName, metav1.GetOptions{}) 24 if getErr != nil { 25 panic(fmt.Errorf("失敗,確認之後再試一下唄~: %v", getErr)) 26 } 27 result.Spec.Replicas = int32Ptr(int32(num)) 28 _, updateErr := deploymentsClient.Update(result) 29 return updateErr 30 }) 31 if retryErr != nil { 32 panic(fmt.Errorf("擴容出現問題,請檢查呼叫~: %v", retryErr)) 33 }