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:
- El nombre del archivo debe comenzar con «kubectl-» y no debe contener extensión.
- El archivo debe ser ejecutable.
- 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!