Kubernetes: How to write a kubectl plugin
Hacktoberfest is almost over but since there’re plenty of opportunities to contribute, I decided to take over the task of re-writing a
kubectl plugin called
For those of you who are not familar with
kubectl, it’s the CLI tool to work with Kubernetes.
In this post I’d like to shed some light on krew and what’s necessary to create your very own plugin. Okay, so what’s krew?
Krew is one of the many Kubernetes Special Interest Groups (SIG) and aims at solving the package management issue for
kubectl. There’s a limited amount of core functionality that ships with
kubectl so krew is all about allowing developers to create their own extensions and contribute them back to the community. All available plugins are stored in the krew-index, a central repo that plugin maintainers use to publish/update their plugins. If you haven’t used krew before, make sure to install it first.
Some early plugins have been written in Bash and the maintainer was asking the community to take over the re-write in Go/Python and ultimately the maintenance of the plugins.
Since my day job requires me to create & manage Kubernetes-based deployments, I find myself in need of decoding secrets all the time.
secret - as the name may reveal already - is used to store secret information Base64 encoded. This resource type is often used to populate environment configuration for deployments, to store docker registry auth information or tls secrets.
The typical workflow to decode a secret without
view-secret looks as follows:
kubectl get secret <secret> -o yaml
- Copy base64 encoded secret
echo "b64string" | base64 -d
This gets quite cumbersome especially if you just want to check the entirety of a secret to see if everything looks ok.
There are solutions like kubedecode or the previous view-secret implementation that aim at solving this problem but lack either native
kubectl integration, are outdated/not maintained anymore or require you to always provide e.g. the
namespace as a parameter.
So I went ahead and created a new implementation for view-secret that is backward-compatible to the existing implementation but also adds a new capability, namely decoding all contents of a secret. My contribution has been accepted and the plugin is available now, so let me walk you through the process.
As it turns out, creating your own plugin is super simple and well documented here. All you have to do is create a binary with the prefix
kubectl-, make it executable and place it somewhere in your
$PATH. A sample plugin can be as easy as this:
# kubectl-hello plugin cat <<EOF > kubectl-hello #!/usr/bin/env bash echo "hello from krew" EOF # Make executable chmod +x kubectl-hello # Copy into some $PATH location cp kubectl-hello /usr/local/bin # Run plugin kubectl hello ## prints "hello from krew"
Since my language of choice for this project was Go, I created a new project and added integrations such as GoReleaser to simplify shipping the binary for mulitple platforms and Travis CI to automate running builds/creating releases. To simplify the build/test process I also added a
At this point my project repo had the following layout:
cmd kubectl-view-secret.go pkg cmd view-secret.go view-secret_test.go go.mod go.sum .goreleaser.yml .travis.yml Makefile
The established workflow was pretty straight-forward:
- push changes to master –> triggers travis to run tests
- tag commit –> triggers travis to use goreleaser
I previously wrote about the usage of
Makefiles in Go projects but for this project the targets are much simpler:
SOURCES := $(shell find . -name '*.go') BINARY := kubectl-view-secret build: kubectl-view-secret test: $(SOURCES) go test -v -short -race -timeout 30s ./... $(BINARY): $(SOURCES) CGO_ENABLED=0 go build -o $(BINARY) -ldflags="-s -w" ./cmd/$(BINARY).go
For the actual implementation I used spf13/cobra to parse flags and process user input. To get the secret contents I use
exec.Command thus shelling out to the OS instead of using the kubernetes go client or cli runtime as they add a huge overhead for such a small functionality.
After I finished the implementation, all I had to do was update the
plugins/view-secret.yaml spec in the krew index to use my new plugin. This meant changing the plugin description, the download links for the new binaries and the
sha256 checksums. Once the Pull Request got merged, the local plugin index had to be updated via
kubectl krew update and the plugin can be installed via
kubectl krew install view-secret.
Now the workflow to decode secrets is as simple as this:
# print secret keys kubectl view-secret <secret> # decode specific entry kubectl view-secret <secret> <key> # decode all secret contents kubectl view-secret <secret> -a/--all # print keys for secret in different namespace kubectl view-secret <secret> -n/--namespace foo # suppress info output kubectl view-secret <secret> -q/--quiet
This was my first CNCF contribution & I’m happy about the feedback I got from @ahmetb & @corneliusweig throughout the process.
The full plugin code is available on GitHub.
Thanks for reading! As always please reach out if you have any questions.
Tags: krew, kubectl, plugin, kubernetes, k8s, cncf, hacktoberfest | Modify on GitHub