Kubectl外掛開發及開源釋出分享
前言
十年雲端計算浪潮下,DevOps、容器、微服務等技術飛速發展,雲原生成為潮流。企業雲化從“ON Cloud”走向“IN Cloud”,成為“新雲原生企業”,新生能力與既有能力立而不破、有機協同,實現資源高效、應用敏捷、業務智慧、安全可信。整個雲原生概念很大,細化到可能是我們在真實場景中遇到的一些小問題,本文就針對日常工作中遇到的自己的小需求,及解決思路方法,分享給大家。
一 背景
在我日常使用kubectl檢視k8s資源的時候,想直接檢視對應資源的容器名稱和映象名稱,目前kubectl還不支援該選型,需要我們describe然後來檢視,對於叢集自己比較多,不是很方便,因此萌生了自己開發kubectl 外掛來實現該功能。
二 相關技術
首先需要呼叫kubernetes需要使用client-go專案來實現對Kubernetes資源的獲取,對於外掛使用Golang語言開發,因為是客戶端執行,為了方便整合到及命令列工具,採用和K8s相同的命令列腳手架工具Cobra,最後將其開源釋出到Github。
2.1 Golang
在雲原生開發中,Google非常多的開源專案都是使用Golang開發,其跨平臺編譯後可以釋出到多個平臺,我們開發的外掛基於Golang,後續也就支援多平臺使用。
2.2 Cobra
Cobra是一個命令列程式庫,其是一個用來編寫命令列的神器,提供了一個腳手架,用於快速生成基於Cobra應用程式框架。我們可以利用Cobra快速的去開發出我們想要的命令列工具,非常的方便快捷。
2.3 Client-go
在K8s運維中,我們可以使用kubectl、客戶端庫或者REST請求來訪問K8S API。而實際上,無論是kubectl還是客戶端庫,都是封裝了REST請求的工具。client-go作為一個客戶端庫,能夠呼叫K8S API,實現對K8S叢集中資源物件(包括deployment、service、ingress、replicaSet、pod、namespace、node等)的增刪改查等操作。
2.4 krew
Krew 是 類似於系統的apt、dnf或者brew的 kubectl外掛包管理工具,利用其可以輕鬆的完成kubectl 外掛的全上面週期管理,包括搜尋、下載、解除安裝等。
kubectl 其工具已經比較完善,但是對於一些個性化的命令,其宗旨是希望開發者能以獨立而緊張形式釋出自定義的kubectl子命令,外掛的開發語言不限,需要將最終的腳步或二進位制可執行程式以kubectl-
的字首命名,然後放到PATH中即可,可以使用kubectl plugin list
檢視目前已經安裝的外掛。
2.4 Github釋出相關工具
- Github Action
如果你需要某個 action,不必自己寫複雜的指令碼,直接引用他人寫好的 action 即可,整個持續整合過程,就變成了一個 actions 的組合。Github是做了一個商店的功能。這樣大家就可以自己定義自己的Action,然後方便別人複用。同時也可以統一自己的或者組織在構建過程中的一些公共流程。
- gorelease
GoReleaser 採用 Golang 開發,是一款用於 Golang 專案的自動釋出工具。無需太多配置,只需要幾行命令就可以輕鬆實現跨平臺的包編譯、打包和釋出到 Github、Gitlab 等版本倉庫種。
三 外掛規劃
- 外掛命名為:kubectl-img
- 目前僅簡單實現一個image命令,用於檢視不同資源物件(deployments/daemonsets/statefulsets/jobs/cronjobs)的名稱,和對應容器名稱,映象名稱。
- 支援json格式輸出。
- 最後將其作為krew外掛使用。
- 可以直接根據名稱空間來進行檢視對應資源。
四 開發
4.1 專案初始化
- 安裝cobra
在開發環境中安裝cobra,後去基於改命令列工具來生成專案腳手架,K8s中很多組建也是用的改框架來生成的。
go get -v github.com/spf13/cobra/cobra
- 初始化專案
$ cobra init --pkg-name kubectl-img
$ ls
LICENSE cmd main.go
$ tree
├── LICENSE
├── cmd
│ └── root.go
└── main.go
- 建立go mod,下載相關包
go mod init github.com/redhatxl/kubectl-img
4.2 增加子命令
增加一個子命令image,在此為我們的外掛新增子命令。
$ cobra add image
4.3 新增引數
通過子命令+flag形式,顯示不同的資源映象名稱。
``` func Execute() { cobra.CheckErr(rootCmd.Execute()) }
func init() { KubernetesConfigFlags = genericclioptions.NewConfigFlags(true) imageCmd.Flags().BoolP("deployments", "d", false, "show deployments image") imageCmd.Flags().BoolP("daemonsets", "e", false, "show daemonsets image") imageCmd.Flags().BoolP("statefulsets", "f", false, "show statefulsets image") imageCmd.Flags().BoolP("jobs", "o", false, "show jobs image") imageCmd.Flags().BoolP("cronjobs", "b", false, "show cronjobs image") imageCmd.Flags().BoolP("json", "j", false, "show json format") KubernetesConfigFlags.AddFlags(rootCmd.PersistentFlags()) } ```
4.4 實現image命令
註冊子命令,並修改命令使用說明。
``
var imageCmd = &cobra.Command{
Use: "image",
Short: "show resource image",
Long:
show k8s resource image`,
RunE: image,
}
func init() { rootCmd.AddCommand(imageCmd) } ```
4.5 初始化clientset
由於需要呼叫K8s資源,在此我們使用Client-go中的ClientSet來根據使用者輸入的不同flag來獲取不同的資源映象。
``` // ClientSet k8s clientset func ClientSet(configFlags genericclioptions.ConfigFlags) kubernetes.Clientset { config, err := configFlags.ToRESTConfig() if err != nil { panic("kube config load error") } clientSet, err := kubernetes.NewForConfig(config) if err != nil {
panic("gen kube config error")
} return clientSet } ```
4.6 實現檢視資源物件
利用反射實現根據不同資源型別檢視具體對應資源映象及映象名稱功能。
``` func image(cmd *cobra.Command, args []string) error {
clientSet := kube.ClientSet(KubernetesConfigFlags) ns, _ := rootCmd.Flags().GetString("namespace") // 生命一個全域性資源列表 var rList []interface{}
if flag, _ := cmd.Flags().GetBool("deployments"); flag { deployList, err := clientSet.AppsV1().Deployments(ns).List(context.Background(), v1.ListOptions{}) if err != nil { fmt.Printf("list deployments error: %s", err.Error()) } rList = append(rList, deployList) } ... deployMapList := make([]map[string]string, 0) for i := 0; i < len(rList); i++ { switch t := rList[i].(type) { case *kv1.DeploymentList: for k := 0; k < len(t.Items); k++ { for j := 0; j < len(t.Items[k].Spec.Template.Spec.Containers); j++ { deployMap := make(map[string]string) deployMap["NAMESPACE"] = ns deployMap["TYPE"] = "deployment" deployMap["RESOURCE_NAME"] = t.Items[k].GetName() deployMap["CONTAINER_NAME"] = t.Items[k].Spec.Template.Spec.Containers[j].Name deployMap["IMAGE"] = t.Items[k].Spec.Template.Spec.Containers[j].Image deployMapList = append(deployMapList, deployMap) } } ```
4.6 實現輸出
利用table來對結果進行輸出,,同樣擴充套件json輸出
func GenTable(mapList []map[string]string) *table.Table {
t, err := gotable.Create(title...)
if err != nil {
fmt.Printf("create table error: %s", err.Error())
return nil
}
t.AddRows(mapList)
return t
}
最終專案結構:
4.7 整合krew
需要將最終的腳步或二進位制可執行程式以kubectl-
的字首命名,然後放到PATH中即可,可以使用kubectl plugin list
檢視目前已經安裝的外掛。
``` $ kubectl plugin list The following compatible plugins are available:= /usr/local/bin/kubectl-debug - warning: kubectl-debug overwrites existing command: "kubectl debug" /usr/local/bin/kubectl-v1.10.11 /usr/local/bin/kubectl-v1.20.0 /Users/xuel/.krew/bin/kubectl-df_pv /Users/xuel/.krew/bin/kubectl-krew
將自己開發的外掛重新命名為kubectl-img放到可執行路基下
$ cp kubectl-img /Users/xuel/.krew/bin/kubectl-img
$ kubectl plugin list The following compatible plugins are available:= /usr/local/bin/kubectl-debug - warning: kubectl-debug overwrites existing command: "kubectl debug" /usr/local/bin/kubectl-v1.10.11 /usr/local/bin/kubectl-v1.20.0 /Users/xuel/.krew/bin/kubectl-df_pv /Users/xuel/.krew/bin/kubectl-krew /Users/xuel/.krew/bin/kubectl-img ```
4.9 使用
``` $ kubectl img image -h show k8s resource image
Usage: kubectl-img image [flags]
Flags: -b, --cronjobs show cronjobs image -e, --daemonsets show daemonsets image -d, --deployments show deployments image -h, --help help for image -o, --jobs show jobs image -j, --json show json format -f, --statefulsets show statefulsets image
Global Flags: --as string Username to impersonate for the operation --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. --cache-dir string Default cache directory (default "/Users/xuel/.kube/cache") --certificate-authority string Path to a cert file for the certificate authority --client-certificate string Path to a client certificate file for TLS --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to the kubeconfig file to use for CLI requests. -n, --namespace string If present, the namespace scope for this CLI request --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") -s, --server string The address and port of the Kubernetes API server --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use ```
- 檢視資源
```
View the images of all deployments of the entire kubernetes cluster
kubectl img image --deployments
View the images of all deployments of the entire kubernetes cluster
kubectl img image --deployments -n default ```
- 檢視所有資源
```
view all resource
kubectl img image -bedof ```
- json格式輸出
```
Table display is used by default
kubectl img image --deployments -n default -j ```
五 開源釋出
完成程式碼編寫後,為了更多朋友學習交流,將其釋出到github上。
5.1 Github Action
在專案根目錄下建立.github/workflows/ci.yml,檔案內容如下
name: ci
on:
push:
pull_request:
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/[email protected]
- name: Setup Go
uses: actions/[email protected]
with:
go-version: 1.16
- name: GoReleaser
uses: goreleaser/[email protected]
with:
version: latest
args: release --snapshot --rm-dist
5.2 GO Report Card
新增go專案報告:https://goreportcard.com/
5.3 GoReleaser
對於golang專案,可以使用GoReleaser來發佈一個漂亮的release。
由於使用的的 MacOS ,這裡使用 brew
來安裝:
brew install goreleaser
在專案根目錄生成 .goreleaser.yml
配置:
goreleaser init
配置好了以後要記得往 .gitignore
加上 dist
,因為 goreleaser 會預設把編譯編譯好的檔案輸出到 dist
目錄中。
```
This is an example .goreleaser.yml file with some sensible defaults.
Make sure to check the documentation at https://goreleaser.com
before: hooks: # You may remove this if you don't use go modules. - go mod tidy # you may remove this if you don't need go generate - go generate ./... builds: - env: - CGO_ENABLED=0 goos: - linux - windows - darwin archives: - replacements: darwin: Darwin linux: Linux windows: Windows 386: i386 amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: name_template: "{{ incpatch .Version }}-next" changelog: sort: asc filters: exclude: - '^docs:' - '^test:'
project_name: kubectl-img ```
goreleaser 配置好後,可以先編譯測試一下:
注意: 首次使用 goreleaser 要配置 GITHUB_TOKEN ,可以在這裡申請,申請好之後執行下面的命令配置 GITHUB_TOKEN
export GITHUB_TOKEN=<YOUR_TOKEN>
確保沒有問題,那麼就可以操作 git 和 goreleaser 來發布 release 了。
git add .
git commit -m "add goreleaser"
git tag -a v0.0.2 -m "First release"
git push origin main
git push origin v0.0.2
全部搞定後,一行命令起飛:
$ goreleaser release --rm-dist
• releasing...
• loading config file file=.goreleaser.yaml
• loading environment variables
• getting and validating git state
• building... commit=98703b3b9d9ac7f4661c5669c1e164d2cf3675d2 latest tag=v1.0.0
• parsing tag
• running before hooks
• running hook=go mod tidy
• running hook=go generate ./...
• setting defaults
• DEPRECATED: skipped windows/arm64 build on Go < 1.17 for compatibility, check https://goreleaser.com/deprecations/#builds-for-windowsarm64 for more info.
• checking distribution directory
• --rm-dist is set, cleaning it up
• loading go mod information
• build prerequisites
• writing effective config file
• writing config=dist/config.yaml
• generating changelog
• writing changelog=dist/CHANGELOG.md
• building binaries
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_linux_386/kubectl-img
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_linux_amd64/kubectl-img
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_darwin_arm64/kubectl-img
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_linux_arm64/kubectl-img
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_windows_amd64/kubectl-img.exe
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_windows_386/kubectl-img.exe
• building binary=/Users/xuel/workspace/goworkspace/src/github.com/kaliarch/kubectl-img/dist/kubectl-img_darwin_amd64/kubectl-img
• archives
• creating archive=dist/kubectl-img_1.0.0_Linux_i386.tar.gz
• creating archive=dist/kubectl-img_1.0.0_Darwin_x86_64.tar.gz
• creating archive=dist/kubectl-img_1.0.0_Linux_x86_64.tar.gz
• creating archive=dist/kubectl-img_1.0.0_Windows_x86_64.tar.gz
• creating archive=dist/kubectl-img_1.0.0_Linux_arm64.tar.gz
• creating archive=dist/kubectl-img_1.0.0_Windows_i386.tar.gz
• creating archive=dist/kubectl-img_1.0.0_Darwin_arm64.tar.gz
• calculating checksums
• storing release metadata
• writing file=dist/artifacts.json
• writing file=dist/metadata.json
• publishing
• scm releases
• creating or updating release repo=redhatxl/kubectl-img tag=v1.0.0
• release updated url=https://github.com/redhatxl/kubectl-img/releases/tag/v1.0.0
• uploading to release file=dist/checksums.txt name=checksums.txt
• uploading to release file=dist/kubectl-img_1.0.0_Linux_i386.tar.gz name=kubectl-img_1.0.0_Linux_i386.tar.gz
• uploading to release file=dist/kubectl-img_1.0.0_Linux_x86_64.tar.gz name=kubectl-img_1.0.0_Linux_x86_64.tar.gz
• uploading to release file=dist/kubectl-img_1.0.0_Windows_i386.tar.gz name=kubectl-img_1.0.0_Windows_i386.tar.gz
• uploading to release file=dist/kubectl-img_1.0.0_Linux_arm64.tar.gz name=kubectl-img_1.0.0_Linux_arm64.tar.gz
• uploading to release file=dist/kubectl-img_1.0.0_Darwin_x86_64.tar.gz name=kubectl-img_1.0.0_Darwin_x86_64.tar.gz
• uploading to release file=dist/kubectl-img_1.0.0_Windows_x86_64.tar.gz name=kubectl-img_1.0.0_Windows_x86_64.tar.gz
• uploading to release file=dist/kubectl-img_1.0.0_Darwin_arm64.tar.gz name=kubectl-img_1.0.0_Darwin_arm64.tar.gz
• announcing
• release succeeded after 183.24s
檢視釋出好的release
在專案Readme中新增不同平臺的安裝方式。
Linux
``` export release=v1.0.0 curl -L -o kubectl-img.tar.gz https://github.com/redhatxl/kubectl-img/releases/download/${release}/kubectl-img_${release}_Linux_arm64.tar.gz tar -xvf kubectl-img.tar.gz cp kubectl-img /usr/local/bin/kubectl-img
use kubectl krew
cp kubectl-img $HOME/.krew/bin ```
OSX
``` export release=v1.0.0 curl -L -o kubectl-img.tar.gz https://github.com/redhatxl/kubectl-img/releases/download/${release}/kubectl-img_${release}_Darwin_x86_64.tar.gz tar -xvf kubectl-img.tar.gz mv kubectl-img /usr/local/bin/kubectl-img
use kubectl krew
cp kubectl-img $HOME/.krew/bin ```
Windows
In PowerShell v5+
``` $url = "https://github.com/redhatxl/kubectl-img/releases/download/v1.0.0/kubectl-img_1.0.0_Windows_x86_64.tar.gz" $output = "$PSScriptRoot\kubectl-img.zip"
Invoke-WebRequest -Uri $url -OutFile $output Expand-Archive "$PSScriptRoot\kubectl-img.zip" -DestinationPath "$PSScriptRoot\kubectl-img" ```
5.4 Badges 展示神器
這裡介紹一個展示 Badges 的神器:https://shields.io/ 。這個網站提供各種各樣的 Badges ,如果你願意,完全可以把你的 GitHub README.md 填滿,有興趣的同學可以自取。
六 總結
目前實現的比較簡單,以此來拋磚引玉的功能,後期可以進行更多功能或其他外掛的開發,自己動手豐衣足食。從技術角度看,以容器、微服務以及動態編排為代表的雲原生技術蓬勃發展,成為賦能業務創新的重要推動力,並已經應用到企業核心業務。從市場角度看,雲原生技術已在金融、製造、網際網路等多個行業得到廣泛驗證,支援的業務場景也愈加豐富,行業生態日漸繁榮。
本文從日常工作中最小的切入點,從0到1實戰K8s外掛開發並開源的思路及過程,希望相關同學可以一塊交流學習。最近由於業務開發Operator,也在研讀K8s控制器相關程式碼,並做了一些自己的筆記,有興趣的可以一塊交流學習,部落格地址:kaliarch blog。
其他
- 雲原生架構之配置中心-總述
- 雲原生架構之Spring Cloud Kubernetes配置中心方案
- 雲原生架構之SpringCloudKubernetes 服務註冊發現方案(東西流量)
- 雲原生架構之服務發現與註冊-Kubernetes中服務註冊發現
- 雲原生架構之Springboot Gateway K8s 服務註冊發現方案(南北流量)
- 雲原生架構之SpringBoot K8s service服務註冊發現方案(東西流量)
- 雲原生架構之服務發現與註冊-總述
- 雲原生備份恢復工具Velero二開實戰
- Kubernetes安全之KubeEye
- Terraform 整合Ansible 實戰(remote)
- Terraform Gitlab CI簡單整合方案
- 實戰Kubernetes Gitlab CI
- Kubernetes叢集中流量暴露的幾種方案
- Kubectl外掛開發及開源釋出分享
- Client-go原始碼分析之SharedInformer及實戰
- TAPD 整合 GitLab
- Gin框架優雅關機和重啟
- Gin Swagger快速生成API文件
- Golang 視覺化工具之go-callvis
- 跨平臺資料備份工具之restic詳解