# 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:

1. El nombre del archivo debe comenzar con «kubectl-» *Recomiendo que no contenga extensiones.*
2. El archivo debe ser ejecutable.
3. Debe encontrarse ubicado en nuestro **PATH**

Podemos ver qué **plugins** tenemos disponibles utilizando:

```
kubectl plugin list
```

Pueden ver parte de la documentacion [aqui](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/)

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](https://k3s.io/)


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í](https://github.com/ctaglia-sys/kubectl-plugin-demo)

**¡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](https://hub.docker.com/r/kscarlett/nginx-log-generator) 

**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

```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645299627318/byN8PYvMV.png)

### Creamos el kubectl plugins:

Paso 1.-  Crearemos el archivo del plugin llamado kubectl-demo con el siguiente script.

> Esté Script lo conseguí [acá](https://github.com/ctaglia-sys/kubectl-plugin-demo/) 

Puedes revisar el código en [Gist](https://gist.github.com/roxsross/b7652a4fe33a0a01f86a48eb2949ccd5)

```
#!/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.](https://github.com/ishantanu/awesome-kubectl-plugins)

> ¡Recomiendo visitarlos, de vez en cuando me salvan el día!

Nos vemos en la próxima entrada


![simplescreenrecorder-2022-02-19_17.06.09.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1645301595520/ZsQRBEc0E.gif)




