Kubectl Plugins en solo 3 pasos

Introducción

Muchas veces para realizar nuestras tareas diarias nos vemos en la situación de tener que crear herramientas propias para resolver problemas o situaciones a medida. En esta entrada voy a mostrar lo fácil que es y cómo podemos crear un plugin para kubectl.

Un plugin es simplemente un programa ejecutable que permite extender la funcionalidad de kubectl, permitiendonos implementar nuestros propios subcomandos. Es importante mencionar que podemos hacerlo en el lenguaje que más nos guste: Bash, Python, Go, etc…

¿Qué necesitamos?

Existen ciertas condiciones que debemos cumplir para que nuestro plugin funcione:

  1. El nombre del archivo debe comenzar con «kubectl-» y no debe contener extensión.
  2. El archivo debe ser ejecutable.
  3. Debe encontrarse ubicado en nuestro PATH

Y esta es toda la instalación que requerirá. Simple, ¿no?

Podemos ver qué plugins tenemos disponibles utilizando:

kubectl plugin list

Este comando buscará dentro de PATH todos los archivos ejecutables que cumplan con el nombre requerido.

¡Manos a la obra!

Creamos un entorno  de pruebas

Hagamos un simple plugin, más entretenido que el trivial «Hola Mundo!», que envíe los logs de todos pods corriendo a una salida única para poder visualizar dicha salida de manera conjunta. Para hacerlo más entretenido agregaremos el nombre del pod colorido por cada línea de log en el output. Y además podremos seleccionar con las teclas numéricas de 1 a N (donde N es el enésimo pod: 1 < N < 10 por simpleza), filtrar on-the-fly y ver solamente la salida de ese pod. ¡Y todo esto lo haremos en Bash!

Para esta demo vamos a usar una imagen de docker nginx-log-generator que genera fake-logs del Nginx. Primero crearemos un deployment de kubernetes que contendra los pods. Creamos un nuevo archivo llamado fake-logs.yaml con el siguiente contenido:

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

Y aplicamos el deployment:

kubectl create -f fake-logs.yaml

Podemos comprobar que nuestros nuestro deploy esta funcionando:

$ 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

Creamos el plugin:

Primero: Crearemos el archivo de nuestro plugin llamado kubectl-demo con el siguiente 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

 

Segundo: Le daremos permisos de ejecución.

chmod +x kubectl-demo

Tercero: Y último paso, necesitamos que este accesible en nuestro PATH.

ln -s $PWD/kubectl-demo /usr/local/bin/kubectl-demo

A partir de ahora, y sin nada más que hacer, podemos hacer uso de nuestro recién creado plugin.

Podemos comprobar que kubectl está listo para usarlo listando los plugins que encuentra:

$ kubectl plugin list
The following compatible plugins are available:
/home/user/kubectl-demo

 ¡Pongámoslo a prueba!

Mostramos las opciones posibles:

$ 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

A modo de ejemplo de cómo podemos pasar parámetros a nuestros sub-comandos, hemos agregado la opción para permitir no pintar el 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"-"....

Podemos elegir que pod mostrar con los números del 1 a 3 en este caso:

# 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" ....

Y podemos resetear esta vista con el número 0 y volver a tener todos los logs:

===================================================
+ 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 - - ....

Como vemos el script es simple y te invito a que pruebes todas sus opciones, modifiques a tu gusto y extiendas su funcionalidad.

Conclusión:

Hemos visto que es sumamente sencillo crear un plugin para kubectl, basta con programar lo que nuestra imaginación quiera y cumplir con el nombre y ubicación del ejecutable.

Por esta facilidad, no existe excusa para no hacer un plugin prácticamente por cada necesidad específica que necesitemos de kubectl.
También es necesario comentar que existe una gran cantidad de plugins provistos por la comunidad.
¡Vale la pena echar un vistazo!

Espero que este artículo te haya servido de ayuda para aprender algo nuevo y seguir ampliando tus conocimientos.

Te invito a que si necesitas información sobre el mundo DevOps o Kubernetes, nos contactes y sigas revisando nuestro blog para encontrar otras publicaciones útiles. ¡Hasta la próxima!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *