Plugins para kubectl que te harán la vida más fácil al gestionar Kubernetes
Kubernetes y Docker están revolucionando el mundo de la informática, el desarrollo de aplicaciones y en concreto DevSecOps. Ambas tecnologías combinadas nos ofrecen beneficios como escalar y gestionar la implementación de una aplicación o un servicio de manera sencilla utilizando contenedores, hasta el punto de convertirse hoy día en un auténtico estándar para la orquestación.
Como cualquier otra infraestructura, debemos tener precauciones a la hora de su implementación para intentar construirla de manera más segura posible, así como ofrecer el mejor rendimiento final.
Y Muchas veces para realizar nuestras tareas diarias de DevOps tenemos que respirar y afrontar situaciones por eso esta frase de spiderman modificada a mi experiencia:
"Un Habilidad conlleva una gran responsabilidad"
Entonces nos vemos en incendios por los que tenemos que improvisar y hasta crear herramientas propias o tratar de buscar alguna en github que cumpla con la función que necesitamos y de esa manera poder resolver problemas.
En publicación voy a explicar como crear un plugin para kubectl.
Un plugin es simplemente un programa ejecutable que permite extender la funcionalidad de kubectl, permitiendonos implementar nuestros propios subcomandos.
Existen multitud de plugins para kubectl para interactuar y realizar todo tipo de operaciones contra nuestro clúster
Es importante mencionar que podemos hacerlo en el lenguaje que más nos guste: Bash, Python, Go, etc…
¿Qué necesitamos?
Existen ciertas cosas que debemos cumplir para que nuestro plugin funcione:
- El nombre del archivo debe comenzar con «kubectl-» Recomiendo que no contenga extensiones.
- El archivo debe ser ejecutable.
- Debe encontrarse ubicado en nuestro PATH
Podemos ver qué plugins tenemos disponibles utilizando:
kubectl plugin list
Pueden ver parte de la documentacion aqui
Este comando buscará dentro de PATH todos los archivos ejecutables que cumplan con el nombre requerido.
¡Vamos al fuego!
Activamos el entorno de laboratorio
En mi caso tengo un cluster default usando k3s
Hagamos un simple plugin, Algo simple como nuestro día día el famoso «Hola Mundo! Hello World», que envíe los logs de todos pods , agrupados en una sola salida, y para hacerlo más interesante agregamos en el nombre del pod color para no verlo normalito porque marea un poco, y así por cada línea de log en la salida.
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.
Recuerden que el script oficial lo pueden encontrar aquí
¡Y todo esto lo haremos en Bash!
Próximamente estaré subiendo el plugins en Go
Para esta demo vamos a usar una imagen de docker nginx-log-generator que genera fake-logs del Nginx. Lo pueden ubicar en dockerhub
1.- crearemos un deployment con el nombre fake-nginx-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 apply -f fake-nginx-logs.yaml
Podemos comprobar que nuestros nuestro deploy estan corriendo sin problemas:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-fake-logger-6c76fccc4f-xt2mn 1/1 Running 0 21m
my-fake-logger-6c76fccc4f-p965z 1/1 Running 0 21m
my-fake-logger-6c76fccc4f-rb8rx 1/1 Running 0 21m
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
my-fake-logger 3/3 3 3 23m
Creamos el kubectl plugins:
Paso 1.- Crearemos el archivo del plugin llamado kubectl-demo con el siguiente script.
Esté Script lo conseguí acá
Puedes revisar el código en Gist
#!/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
Paso 2.- Le daremos permisos chmod +x para la ejecución.
chmod +x kubectl-demo
Paso 3.- Y ahora necesitamos que el PATH se pueda acceder.
ln -s $PWD/kubectl-demo /usr/local/bin/kubectl-demo
Ahora si si si si si, podemos usar el plugins
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
¡Vamos a ver si funciona a probar el fuego!
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
¡¡¡Vamos a jugar!!!
Outputs
Default:
197.199.245.10 - - [19/Feb/2022:19:44:58 +0000] "HEAD /hybrid/reciprocal%20Persevering.gif HTTP/1.1" 200 1970 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_7 rv:6.0) Gecko/1985-06-12 Firefox/36.0"
156.174.234.141 - - [19/Feb/2022:19:44:59 +0000] "GET /bi-directional/intangible.js HTTP/1.1" 200 2054 "-" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/5321 (KHTML, like Gecko) Chrome/36.0.885.0 Mobile Safari/5321"
1.250.200.49 - - [19/Feb/2022:19:45:00 +0000] "DELETE /parallelism.htm HTTP/1.1" 200 1697 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1 rv:7.0) Gecko/1952-27-09 Firefox/35.0"
239.188.233.47 - - [19/Feb/2022:19:45:01 +0000] "GET /access/Virtual-Open-architected.js HTTP/1.1" 200 1807 "-" "Opera/9.26 (X11; Linux i686; en-US) Presto/2.10.329 Version/13.00"
95.140.57.96 - - [19/Feb/2022:19:45:02 +0000] "GET /Visionary.svg HTTP/1.1" 200 2811 "-" "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_5_4) AppleWebKit/5340 (KHTML, like Gecko) Chrome/37.0.853.0 Mobile Safari/5340"
Podemos elegir que pod mostrar con los números del 1 a 3 ó N en este caso:
1
===================================================
+ Showing logs for:
+ my-fake-logger-6c76fccc4f-xt2mn
===================================================
[my-fake-logger-6c76fccc4f-xt2mn] 81.131.215.98 - - [19/Feb/2022:19:45:20 +0000] "GET /emulation/Mandatory%20Triple-buffered.hmtl HTTP/1.1" 200 882 "-" "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_6_6) AppleWebKit/5320 (KHTML, like Gecko) Chrome/38.0.800.0 Mobile Safari/5320"
[my-fake-logger-6c76fccc4f-xt2mn] 141.124.220.116 - - [19/Feb/2022:19:45:21 +0000] "GET /orchestration-framework/radical-upward-trending_Compatible.svg HTTP/1.1" 200 894 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/5331 (KHTML, like Gecko) Chrome/40.0.897.0 Mobile Safari/5331"
[my-fake-logger-6c76fccc4f-xt2mn] 81.22.229.76 - - [19/Feb/2022:19:45:22 +0000] "PATCH /Profit-f
Y podemos inicializar número 0 y volver a tener todos los logs:
0
===================================================
+ Showing logs for:
+ All Pods
===================================================
9.12 (Macintosh; U; Intel Mac OS X 10_5_5; en-US) Presto/2.8.341 Version/12.00"
[my-fake-logger-6c76fccc4f-rb8rx] 1.123.142.130 - - [19/Feb/2022:19:46:16 +0000] "GET /service-desk%20migration/context-sensitive.hmtl HTTP/1.1" 200 1635 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/5312 (KHTML, like Gecko) Chrome/37.0.859.0 Mobile Safari/5312"
[my-fake-logger-6c76fccc4f-rb8rx] 44.234.216.99 - - [19/Feb/2022:19:46:17 +0000] "GET /Virtual.php HTTP/1.1" 200 913 "-" "Opera/10.51 (X11; Linux i686; en-US) Presto/2.8.197 Version/12.00"
Como vemos el script es simple, sencillo y cero estress y te invito a que pruebes todas sus opciones, modifiques , no hay limites en esto.
Y si vamos a una conclusión:
Vieron que es facil crear un plugins para kubectl , basta con tener una idea, programarlos y sin miedo al éxito.
Todo de acuerdo a nuestras necesidades y el requerimiento.
Pueden buscar en Github hay una banda de cosas pero igual siempre revisen plugins provistos por la comunidad.
¡Recomiendo visitarlos, de vez en cuando me salvan el día!
Nos vemos en la próxima entrada