Introduction
Many times to fullfill our daily tasks we find ourselves in the situation of having to build our own tools to solve specific problems or situations. In this note I am going to show you how easy it is to create a plugin for kubectl.
A plugin is simply an executable program that allows you to extend the functionality of kubectl, allowing us to implement our own subcommands.
It is important to mention that we can code it in the language we like the most: Bash, Python, Go, etc…
What do we need?
There are certain conditions that we must meet for our plugin to work:
- The file name must begin with: kubectl- and must not contain an extension.
- It must be an executable file.
- It should be located in our $PATH and this will be all the installation it would require. Pretty simple, no?
We can list available plugins on our system using:
kubectl plugin list
This command will search on our PATH for all executable files that meet the required conditions.
Let’s do it!
Create a test environment
Let’s make a simple plugin, more entertaining than the trivial «Hello World!», that sends the logs of all running pods to a single output to be able to view this output jointly.
To make it more entertaining we will add the name of the pod in colors for each log line in the output. And we can also select with the numeric keys from 1 to N (where N is the nth pod: 1 on-the-fly and see only the output of that pod.
And we will do all this in Bash!
For this demo we are going to use a docker image nginx-log-generator that generates Nginx fake-logs. We will first create a kubernetes deployment that will contain the pods. We create a new file called fake-logs.yaml with the following content:
apiVersion: apps/v1 kind: Deployment metadata: name: my-fake-logger spec: template: metadata: name: logger-1 labels: app: logger spec: containers: - name: logger image: kscarlett/nginx-log-generator replicas: 3 selector: matchLabels: app: logger
Apply the deployment:
kubectl create -f fake-logs.yaml
Let’s check that our deploy is working:
$ kubectl get pods NAME READY STATUS RESTARTS AGE my-fake-logger-66dcffbccd-6kx8b 1/1 Running 4 6d2h my-fake-logger-66dcffbccd-7q4tm 1/1 Running 1 3d1h my-fake-logger-66dcffbccd-cff4s 1/1 Running 1 3d1h $ kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE my-fake-logger 3/3 3 3 6d2h
Create the plugin:
First: We will create our plugin file named kubectl-demo with the following script.
#!/bin/bash trap ctrl_c INT function ctrl_c() { echo "**************************************** Bye Bye ****************************************" for pid in ${PIDS[@]} do kill -TERM $pid done rm $NAMED_PIPE rm $sync exit 0 } function colorize() { pod=$1 counter=$2 # colors from 31 to 39 pre_colour="\033[3${counter}m" post_colour="\033[0m" if [ "$colorize_output" = true ] then colour_pod="${pre_colour}[${pod}]${post_colour}" else colour_pod="[${pod}]" fi } function show_logs() { local sync="$1" grep -E -f $sync $NAMED_PIPE & } function banner() { echo "" echo "===================================================" echo "+ Showing logs for:" echo "+ $1" echo "===================================================" echo "" } function start_log() { show_logs $sync shl_pid=$! disown $shl_pid PIDS+=$shl_pid" " } function usage() { echo "~~~~~~~~~~~" echo " U S A G E" echo "~~~~~~~~~~~" echo "Usage: kubectl demo [option]" echo " options:" echo " --no-colorize: no colorize [default: colorize]" echo " -h: Show this help" echo "" echo "When running you can use the numbers 1 to N to filter N-pod and only show it's output." echo "0 resets and shows all outputs again" echo "" } NAMED_PIPE="/tmp/my_named_pipe" PODS=$(kubectl get pods --no-headers=true -o=custom-columns=NAME:.metadata.name) TOTAL_PODS=$(echo $PODS | sed -s 's/ /n/g' | wc -l) colorize_output=true if [[ $@ ]]; then case "$@" in "--no-colorize") colorize_output=false ;; "-h") usage exit 1 ;; *) echo "Invalid option" exit 1 ;; esac fi # create named pipe if [ ! -p $NAMED_PIPE ] then mkfifo $NAMED_PIPE chmod a+rw $NAMED_PIPE fi PIDS=() declare -A pods_index counter=1 for pod in $(echo $PODS) do colour_pod="" colorize $pod $counter kubectl logs -f $pod | awk -v pod_name=$colour_pod '{print pod_name" "$0}' > $NAMED_PIPE & PIDS+=$!" " # save all PIDs pods_index[$counter]=$pod counter=$((counter+1)) done # Trick: Shared memory segment for inter process comunication. sync=/dev/shm/syntest-$$ # allocate a shared memory segment name for this pid echo '' > $sync # init the shm start_log input="*" re='^[0-9]+$' # we match only numbers while true do read -t 0.25 -N 1 input if [[ $input =~ $re ]] && [ "$input" -ge "0" ] && [ "$input" -le "$TOTAL_PODS" ] then if [ "$input" -eq "0" ] then banner "All Pods" echo $ > $sync # grep everything else banner ${pods_index[$input]} echo ${pods_index[$input]} > $sync # grep only pod name fi kill -SIGTERM $shl_pid PIDS=$(echo $PID | sed -e "s/$shl_pid//g" | tr -s " ") # remove unused pid start_log fi done
Second: Set execution permissions
chmod +x kubectl-demo
Third: And last step, we need our script to be accessible from our PATH.
ln -s $PWD/kubectl-demo /usr/local/bin/kubectl-demo
From now on, and with nothing else to do, we can make use of our newly created plugin.
We can check that kubectl is ready to use it by listing the plugins it finds:
$ kubectl plugin list The following compatible plugins are available: /home/user/kubectl-demo
Let’s test it!
We show the possible options:
$ kubectl demo -h ~~~~~~~~~~~ U S A G E ~~~~~~~~~~~ Usage: kubectl demo [option] options: --no-colorize: no colorize [default: colorize] -h: Show this help When running you can use the numbers 1 to N to filter N-pod and only show it's output. 0 resets and shows all outputs again
As an example of how we can pass parameters to our sub-commands, we have added the option to allow not to paint the output.
Outputs
Default:
[my-fake-logger-66dcffbccd-7q4tm] 214.216.236.37--[02/Jan/2021:10:17:17+0000] "GET/moderator/Reduced.cssHTTP/1.1".... [my-fake-logger-66dcffbccd-6kx8b] 132.56.98.34--[02/Jan/2021:10:19:22+0000] "GET/standardization.svgHTTP/1.1"2001908 [my-fake-logger-66dcffbccd-cff4s] 159.240.103.70--[02/Jan/2021:10:24:45+0000] "GET/Virtual.htmHTTP/1.1"2002288"-"....
We can choose which POD want to display with the numbers 1 to 3 in this case:
# 1 =================================================== + Showing logs for: + my-fake-logger-66dcffbccd-6kx8b =================================================== [my-fake-logger-66dcffbccd-6kx8b] 16.211.208.91 - - [02/Jan/2021:10:34:33 +0000] "GET /bottom-line%20Advanced/Upgradable/intermediate.svg HTTP/1.1" ....
And we can reset too default view by using number 0 and have all the logs again:
=================================================== + Showing logs for: + All Pods =================================================== [my-fake-logger-66dcffbccd-7q4tm] 214.216.236.37--[02/Jan/2021:10:17:17+0000] "GET/moderator/Reduced.cssHTTP/1.1"30143"-".... [my-fake-logger-66dcffbccd-6kx8b] 16.211.208.91 - - ....
As we can see, the script is pretty simple and I invite you to try all its options, modify it to your liking and extend its functionality.
Conclusion
We saw that it is extremely easy to create a kubectl plugin, it is enough to program what our imagination wants and comply with the executable name and location.
Because of this facility, there is no excuse for not making a plugin for practically every specific need. It is also necessary to comment that there is a large number of plugins provided by the community. It’s worth taking a look!
I hope this note has helped you to learn something new and continue to expand your knowledge.
I invite you if you need information about the DevOps world or Kubernetes, contact us and keep checking our blog to find other useful publications.