Preface
Under the ten-year cloud computing wave, DevOps, containers, microservices and other technologies are developing rapidly, and cloud-native has become a trend. Enterprises are moving from “ON Cloud” to “IN Cloud” and becoming “new cloud-native enterprises”, where new capabilities and existing capabilities are established but not broken, with organic synergy to achieve Resource efficiency, application agility, business intelligence, security and trustworthiness. The whole concept of cloud-native is very big, and it is so detailed that we may encounter some small problems in the real scenario, this article will share with you the small demands and solutions we encounter in our daily work.
Background
In my daily use of kubectl to view K8s resources, I want to directly view the corresponding resources of the container name and image name, kubectl does not support the selection, we need to describe then to view, for the cluster itself more, not very convenient, so the development of their own kubectl plug-in to achieve this function.
The first need to call Kubernetes requires the use of client-go project to achieve access to Kubernetes resources, for the plug-in using Golang language development, because it is client-side execution, in order to facilitate the integration to and command-line tools, using the same command-line scaffolding tool Cobra and K8s, and finally released it open source to GitHub.
Golang
In cloud native development, many of Google’s open source projects are developed using Golang, which can be distributed to multiple platforms after cross-platform compilation, and the plug-ins we develop are based on Golang and subsequently support multi-platform use.
Cobra
Cobra is a command line library that is a powerful tool for writing command lines and provides a scaffold for quickly generating Cobra-based application frameworks. We can use Cobra to quickly and easily develop the command line tools we want.
Client-go
In K8s operations, we can use kubectl, client libraries or REST requests to access the K8s API, and in fact, both kubectl and client libraries are tools that encapsulate REST requests. client-go, as a client library, can call the K8s API and implement operations on resource objects in the K8s cluster, including client-go is a client library that can call the K8s API to add, delete, modify, and query resource objects (including deployment, service, Ingress, ReplicaSet, Pod, Namespace, Node, etc.) in a K8s cluster.
krew
Krew is a package management tool for kubectl plugins, similar to apt, dnf or brew, which allows you to easily manage the full cycle of kubectl plugins, including search, download, uninstall, etc.
The kubectl tool is already relatively complete, but for some personalized commands, the goal is to allow developers to release custom kubectl subcommands in an independent and intense form. Plugins can be developed in any language. You need to name the final footer or binary executable with the prefix kubectl-
and put it in the PATH. You can use the kubectl plugin list
to see which plugins are currently installed.
If you need an Action, you don’t have to write your own complex script, you can just reference someone else’s Action and the whole continuous integration process becomes a combination of Actions. This allows people to define their own Action, which can then be easily reused by others. It is also possible to unify your own or organize some public processes in the build process.
Developed in Golang, GoReleaser is an automated release tool for Golang projects. Without much configuration, you can easily compile, package and publish cross-platform packages to Github, Gitlab and other repositories with just a few lines of command.
Plugin planning
- The plugin is named: kubectl-img.
- Currently only a simple implementation of an image command to view the names of different resource objects (deployments/daemonsets/statefulsets/jobs/cronjobs), and the corresponding container names, image names.
- JSON format output is supported.
- Finally use it as a krew plugin.
- You can view the corresponding resources directly based on the namespace.
Development
Project initialization
Install Cobra in your development environment and go to the command line tool to generate project scaffolding based on this framework, which is also used to generate many of the components in K8s.
1
|
go get -v github.com/spf13/cobra/cobra
|
Adding a subcommand
Add a subcommand image, add a subcommand to our plugin here.
Add parameters
Display different resource image names by subcommand+flag form.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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())
}
|
Implement the image command
Register subcommands and modify command usage instructions.
1
2
3
4
5
6
7
8
9
10
|
var imageCmd = &cobra.Command{
Use: "image",
Short: "show resource image",
Long: `show k8s resource image`,
RunE: image,
}
func init() {
rootCmd.AddCommand(imageCmd)
}
|
Initialize clientset
Since we need to call K8s resources, here we use ClientSet in Client-go to get different resource images based on different flags entered by the user.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 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
}
|
View resource objects
Use reflection to view specific resource images and image names based on different resource types.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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)
}
}
|
Implementing Output
Use Table to output the results, also extending JSON output.
1
2
3
4
5
6
7
8
9
10
|
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
}
|
Final project structure.
Integrating krew
You need to name the final footer or binary executable with the prefix kubectl-
and put it in the PATH. You can use the kubectl plugin list
to see which plugins are currently installed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
$ 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
|
Use
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
$ 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 Resources
1
2
3
4
|
# 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 resources
1
2
3
|
# view all resource
kubectl img image -bedof
|
-
JSON formatted output
1
2
|
# Table display is used by default
kubectl img image --deployments -n default -j
|
Open Source Publishing
Once you’ve finished writing the code, you’ll publish it to GitHub so that more people can learn and share it.
Github Action
Create a .github/workflows/ci.yml
file in the project root directory with the following contents.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
name: ci
on:
push:
pull_request:
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Setup Go
uses: actions/setup-go@v1
with:
go-version: 1.16
- name: GoReleaser
uses: goreleaser/goreleaser-action@v1
with:
version: latest
args: release --snapshot --rm-dist
|
GO Report Card
Add a Go project report: https://goreportcard.com/
GoReleaser
For Golang projects, you can use GoReleaser to make a nice Release.
Since macOS is used, here’s how to install it using brew
.
1
|
brew install goreleaser
|
Generate the .goreleaser.yml
configuration in the project root directory.
Once configured, remember to add dist
to .gitignore
, as goreleaser will output the compiled files to the dist
directory by default.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
# 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
|
After GoReleaser is configured, you can first compile and test it by.
Note: To configure GITHUB_TOKEN for the first time using GoReleaser, you can apply for it here, and run the following command to configure GITHUB_TOKEN
after the application is done.
1
|
export GITHUB_TOKEN=<YOUR_TOKEN>
|
Make sure there are no problems, then you can run Git and GoReleaser to release the release.
1
2
3
4
5
|
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
|
After all is done, execute the following command to publish.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
$ 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
|
Check out the Release that was released.
Add the installation method for different platforms in the project README.
Linux
1
2
3
4
5
6
|
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
1
2
3
4
5
6
7
|
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+
1
2
3
4
5
|
$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"
|
Here’s a great tool for displaying Badges: https://shields.io/. This site offers a wide variety of Badges, and you can fill up your GitHub README.md with them if you want.
Summary
The current implementation is relatively simple, as a way to throw the function, later you can carry out more functions or other plug-in development. From a technical perspective, cloud-native technologies represented by containers, microservices and dynamic orchestration are flourishing and have become an important driving force for enabling business innovation, and have been applied to the core business of enterprises. From the market perspective, cloud-native technologies have been widely verified in many industries such as finance, manufacturing, and Internet, and the business scenarios supported are getting richer and richer, and the industry ecology is becoming more and more prosperous.