Skip to content

Bitácora

Agustin Cao edited this page Dec 19, 2021 · 35 revisions

Proceso de Analisis y Desarrollo del Proyecto

Investigación

16 de Agosto: me pase una hora leyendo la documentación de docker en https://docs.docker.com/get-started/.

29 de Agosto: Recopilar información sobre docker y kubernetes.

¿Qué es Kubernetes? https://tanzu.vmware.com/developer/guides/kubernetes/what-is-kubernetes/

Introducción a Docker Containers en Kubernetes: https://tanzu.vmware.com/developer/guides/kubernetes/what-is-kubernetes/

Escribimos la plantilla de presentación del proyecto y el powerpoint correspondiente.

02 de Septiembre: Información sobre sistemas de Alta Disponibilidad (High Availability).

https://us.sios.com/what-we-do/high-availability/

https://medium.com/velotio-perspectives/demystifying-high-availability-in-kubernetes-using-kubeadm-3d83ed8c458b

05 de Septiembre: hecho el tutorial oficial de docker: https://docs.docker.com/get-started

Documentación Docker: https://docs.docker.com/get-started/

Iniciando con Docker Containers en Kubernetes: https://tanzu.vmware.com/developer/guides/kubernetes/what-is-kubernetes/

Alta disponibilidad: https://us.sios.com/what-we-do/high-availability/

Alta disponibilidad con Kubernetes: https://medium.com/velotio-perspectives/demystifying-high-availability-in-kubernetes-using-kubeadm-3d83ed8c458b

Tutorial oficial de docker: https://docs.docker.com/get-started

11 de Septiembre: experimentos Dockerizando un proyecto personal y desplegándolo a Heroku

15 de Septiembre: lectura de los conceptos teóricos de Kubernetes

16 de Septiembre: más conceptos teóricos de Kubernetes.

19 de Septiembre: hecho el tutorial interactivo oficial de Kubernetes

¿Qué es Kubernetes? https://tanzu.vmware.com/developer/guides/kubernetes/what-is-kubernetes/

Documentación oficial de Kubernetes: https://kubernetes.io/docs/home/

29 de Septiembre: Puesta en marcha del sistema

Recibidas las SBC, se procedió a evaluar el estado y los materiales.

El sistema operativo que se utilizará para el proyecto en cada una de las Raspberry Pi será Raspbian 10 (Buster) con kernel Linux versión 5.10. Se comprobó utilizando los comandos

uname -r
cat /etc/os-release

Para no tener que modificar la configuración de Access Point de las Raspberry Pi, se las conectó mediante cables ethernet a un access point.

El Access Point se encuentra alejado del router, por lo que se lo configuró para que funcione en modo puente WDS, a fin de brindar conexión a internet a las Raspberry Pi.

Modelo del Access Point: TpLink TL-WR741ND v4.22

Guia de configuración para modo WDS Bridge

Se estableció una IP fija para cada RPi, modificando la configuración del archivo /etc/dhcpcd.conf

sudo nano /etc/dhcpcd.conf

Dentro del mismo, se agregó al final del archivo:

interface eth0
    #reemplazar 'x' por el número identificador de la CBC
    static ip_address=192.168.0.20x/24
    static routers=192.168.0.1
    static domain_name_servers=192.168.0.1

x es el número de la RPi, 1 o 2.

Esta configuración permite que las Raspberry Pi operen via cable ethernet y sean consistentes al conectarse a cualquier red cuyo router tenga la direccion 192.168.0.1, y las direcciones 192.168.0.201/24 y 192.168.0.202/24 se encuentren disponibles.

Con la finalidad de ahorrar energia y reducir interferencias, se desactiva las antenas de WiFi de las Raspberry Pi.

sudo rfkill block wifi

Si se quiere volver a activarlas:

sudo rfkill unblock wifi

Por ultimo, se comprobó que ninguna de las RPis se encontrara funcionando en condiciones anormales o que pudiesen afectar su rendimiento

vcgencmd get_throttled

Referencia documentación Raspberry Pi

Si deseamos interpretar la respuesta, convertimos el valor hexadecimal que devuelve el comando y comparamos bit a bit. En nuestro caso, la respuesta fue 0x0, por lo que no se encuentran condiciones anormales.

Instalación de Docker

A fin de realizar pruebas con contenedores en el sistema antes de comenzar con el uso de un orquestador, instalamos docker y comprobamos su funcionamiento.

Para instalarlo, utilizamos un script recomendado por docker para instalar dicho sistema en casi cualquier distribucion de linux

curl -sSL https://get.docker.com/ | sh

Agregamos al usuario actual al grupo "docker" para poder utilizar los comandos de docker sin necesidad de ser superusuario

sudo usermod -aG docker $USER

comprobamos que docker esté corriendo utilizando

Iniciamos el daemon de docker

sudo systemctl start docker
docker version

OPCIONAL: Aparentemente, al instalar docker se agregó la entrada de que permite iniciar el daemon de docker junto con el resto del sistema. Si esta funcionalidad es necesaria, puede activarse utilizando

sudo systemctl enable docker

Si se desea desactivar la misma

sudo systemclt disable docker

Como prueba, iniciamos un contenedor con una imagen de Nginx (un popular webserver).

docker container run --rm -p 80:80 nginx
  • --rm indica a docker que debe eliminar el contenedor una vez terminada su ejecucion
  • -p indica los puertos a exponer y ligar entre la SBC y en la red de contenedores, respectivamente.

Luego, utilizamos un navegador desde cualquier computadora conectada a la misma red que las SBC e insertamos la direccion IP de aquella que hemos configurado con el servidor Nginx. Debería aparecer un mensaje como el siguiente.

Para finalizar el proceso, simplemente pulsamos ctrl + c


24 de Octubre: se buscó un proyecto semilla para facilitar la configuración inicial de la aplicación de prueba. Despues de probar con varios proyectos públicos encontrados en github, la gran mayoría de los cuales o no incluían una base de datos o no estaban demasiado desactualizados como para funcionar, se terminó optando por el siguiente: https://github.com/rgaino/docker-node-react-mysql-boilerplate

Hecho el git pull, el proyecto se puede levantar usan el comando:

docker-compose up

Una vez que se termino de levantar, se corrobora que el contenedor esté corriendo correctamente con el comando:

docker ps

Luego, a modo de prueba se procede a crear una nueva tabla en la BD. Para esto se utilizó el programa DBeaver. La conexión a la base de datos local, si no se cambia la configuración del proyecto semilla, se configura de la siguiente manera:

Server Host: localhost Port: 3306 Database: boilerplate_db Username: dbuser Password: dbuserpwd Driver: MySQL

Se procede a crear una tabla sencilla usando la interfaz gráfica de DBeaver. El código DDL generado es el siguiente:

CREATE TABLE boilerplate_db.Sensores ( temp DOUBLE NULL, id BIGINT UNSIGNED auto_increment NOT NULL, CONSTRAINT Sensores_PK PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;

Se persisten los cambios y se corrobora que la base de datos está funcionando correctamente.


7 de noviembre:

Se investigaron los framework express y sequelize de javascript para escribir una API REST y manejar los ORM respectivamente.


Pruebas del sensor

13 de noviembre:

Para las pruebas con el sensor, se decidió ejecutar directamente sobre la placa un script en python para comprobar su funcionamiento.

El sensor utilizado es el DHT11, que es un sensor de temperatura y humedad. La placa elegida para correr el script es la misma que utilizaremos como worker en el cluster.

https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf

Se trata de un sensor que puede medir temperaturas en un rango de 0ºC a 50ºC con una precision de ±2ºC y humedades en un rango de 20%HR a 90%HR con una precision de ±5%HR. La resolución minima en ambos casos es de 1ºC y 1%HR respectivamente.

HR = Humedad Relativa

En su paquete original, el sensor requiere de una resistencia de pull up de al rededor de 5k en el pin de datos para funcionar. Sin embargo, la version que nosotros poseemos es la de un modulo que ya cuenta con dicha resistencia, mas un capacitor de desacople ubicado en el pin de alimentación para prevenir fallas por cambios bruscos en la alimentación (filtro pasa-bajos).

http://tutorialesdeelectronicabasica.blogspot.com/2021/03/que-es-el-condensador-de.html

Para conectarlo, se utilizaron los pines 4 (5V PWR) y 6 (GND) para alimentación, y 5 (GPIO 3) para la transmision de datos. A su vez, fue necesario instalar los paquetes python3-pip y python3-dev para utilizar el modulo.

El programa de prueba consiste en un simple script que lee los datos del sensor y los muestra por consola. Se realizan lecturas cada 5 segundos. Un detalle que fue descubierto es que dicho sensor es propenso a fallas al leer, sin importar del tiempo de espera entre lecturas. Por lo tanto, se utilizó una funcion especial de la libreria de Adafruit, la cual realiza 15 lecturas sucesivas en intervalos de 2 segundos hasta obtener una lectura valida. Esto reduce la probabilidad de obtener una lectura erronea.

https://learn.adafruit.com/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging/python-setup

las librerias necesarias para la ejecucion del script son Adafruit_DHT, version 1.4.0 y time. Raspbian, por defecto, no trae instalado el manejador de paquetes de python, pip. Por lo tanto, se recomienda proceder con los siguientes comandos antes de correr el script.

    sudo apt-get install python3-dev python3-pip
    sudo python3 -m pip install --upgrade pip setuptools wheel
    sudo pip3 install Adafruit_DHT

El programa de prueba consiste en el siguiente script:

import Adafruit_DHT
import time

DATA_PIN = 3
SENSOR = Adafruit_DHT.DHT11

while True:

    humidity, temperature = Adafruit_DHT.read_retry(SENSOR, DATA_PIN)

    if ((temperature != None)) and ((humidity != None)):
        print("Temperatura={0:0.1f}ºC | Humedad={1:0.1f}%HR".format(temperature, humidity))
    else:
        print("Falla de lectura. Reintentando...")

    time.sleep(5)

El mismo se encuentra dentro del archivo dht11_sensor_test.py, dentro del directorio dht11_sensor. Si se desea probarlo, copiar el script dentro de la Raspberry Pi que posea el sensor conectado y simplemente correr el mismo dentro del directorio donde se encuentre guardado mediante el comando:

    python3 dht11_sensor_test.py


Preparativos para el cluster con K3s

20 de noviembre:

Enabling cgroups for Raspbian Busterhttps://rancher.com/docs/k3s/latest/en/installation/installation-requirements/

Enabling cgroups for Raspbian Buster & Enabling legacy iptables on Raspbian Buster: https://rancher.com/docs/k3s/latest/en/advanced/

K3s necesita tener activado algo llamado cgroup para poder ejecutar los contenedores. Raspbian buster tiene dicha caracteristica desactivada por defecto. Para habilitarla:

modificar el archivo /boot/cmdline.txt

    sudo nano /boot/cmdline.txt

agregar al final

    cgroup_memory=1 cgroup_enable=memory

Para operar, todo debe realizarse siendo root desde este punto

    sudo su -

K3s necesita ademas utilizar algo llamado Legacy IP Tables. Raspbian buster utiliza por defecto nftables, por lo que debemos configurarlo para utilizar legacy iptables

    sudo iptables -F
    sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
    sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

reiniciamos el sistema

    sudo reboot

Instalación de K3s en el nodo maestro

21 de noviembre:

Una vez realizados los preparativos, instalamos K3s en modo superusuario

Tener en cuenta que K3s usa por default a containerd como el Container Runtime. A fin de simplificar la guia, pasaremos a utilizar containerd.

el siguiente comando se encarga de descargar un script provisto por Rancher (los creadores de K3s), el cual se encargará de realizar la instalación

A su vez, rancher recomienda una herramienta Rancher, que facilita el manejo de distintas plataformas de Kubernetes. Aunque no es necesaria para nuestro caso, dejaremos la instalación de K3s lista en caso de que decidamos probarla, ya que según rancher, no causará problemas en caso de dejarse activada.

https://rancher.com/docs/k3s/latest/en/quick-start/ https://rancher.com/docs/rancher/v2.5/en/cluster-provisioning/registered-clusters/

    sudo su -

    curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644

Una vez finalizada la instalación, debido a que la capacidad de las SBC es bastante limitada y que un orquestador de Kubernetes es algo pesado, es recomendable volver a reiniciar el sistema para finalizar cualquier proceso que no sea necesario.

A diferencia de antes,esperar algunos minutos hasta que la actividad del cpu baje antes de operar sobre el sistema. (se recomienda utilizar htop para monitorear la actividad)

Luego de unos minutos, comprobamos el estado del sistema utilizando haciendo que liste los nodos que tiene conectados. En este caso, solo se listará a si mismo, ya que no hay otros nodos.

    sudo su -

    kubectl get nodes

Instalacion de K3s en nodos worker

21 de noviembre:

Es necesario realizar los mismos preparativos que para el nodo maestro, pero la instalación cambia un poco.

Para instalar K3s en un nodo trabajador, debemos tener la direccion ip y el token de autenticación del nodo maestro.

La dirección ip ya la conocemos por haberla seteado antes. de todas formas, si no se la conoce, puede encontrarse utilizando el comando

    ipfconfig -a | grep -A 7 "eht0"

Utilizamos eth0 porque es la interfaz que configuramos inicialmente

El Token de autenticación puede encontrarse en el archivo /var/lib/rancher/k3s/server/node-token, por lo que simplemente hacemos un cat para verlo y copiarlo.

    cat /var/lib/rancher/k3s/server/node-token

Teniendo la dirección ip y el token, iniciamos una sesion mediante ssh con uno de los nodos trabajadores. En la instalación, seteamos dichos parametros mediante las variables de entorno K3S_URL y K3S_TOKEN Es importante mencionar que para que K3s funcione, cada nodo debe tener un hostname diferente. En nuestro caso, todos los nodos tienen por nombre 'raspberry', por lo que para cambiarlo, editamos tambien la variable de ambiente correspondiente al nombre del nodo, K3S_NODE_NAME.

    sudo su -

    curl -sfL https://get.k3s.io | K3S_URL=https://[ip_del_nodo_maestro]:6443 K3S_TOKEN=[token_del_nodo_maestro] K3S_NODE_NAME="[nombre_del_nuevo_nodo]" sh -

En nuestro caso, utilizamos la configuración:

    sudo su

    curl -sfL https://get.k3s.io | K3S_URL=https://192.168.0.201:6443 K3S_TOKEN=K1001dec79df9dfa648fe3633367dc8cdfd182bb7260444e40ebafa9fbcf5950320::server:a2aa8e621c89ee0bbd309b3d11c191d0 K3S_NODE_NAME="worker1" sh -

Corriendo el script en un contenedor

28 de noviembre:

Para utilizar dicho script con docker, primero debemos crear una imagen. Y antes de ello, debemos crear un dockerfile para especificar como crearla.

Tambien hay que tener en cuenta que, como el script debe correrse en una raspberry pi, y la imagen va a tener un SO para una arquitectura ARM como es la de nuestra SBC, lo mas eficiente es crear directamente la imagen desde la raspberry pi.

Dockerfile Reference: https://docs.docker.com/engine/reference/builder/

Utilizamos nano para poder crear y editar el archivo.

    nano dockerfile

Y en el mismo colocamos.

FROM arm32v7/python:3.7.12-buster

RUN apt-get update && apt-get install -y python3-pip=18.1-5 rpi.gpio=0.6.5-1

RUN python3 -m pip install --upgrade pip setuptools wheel

RUN pip3 install Adafruit_DHT==1.4.0

COPY dht11_sensor_test.py ./

CMD [ "python3", "DHT11_sensor_test.py" ]

Corriendo pruebas, nos dimos cuenta que, para funcionar en contenedores de forma adecuada, debemos hacerle una pequeña modificacion a nuestro script. El mismo funciona, sin embargo, dentro del contenedor, los mensajes de print no se muestran hasta detener el script. Esto se debe a como maneja python los buffers de salida. Por lo tanto, debemos agregar el parametro "flush=True" al print, para que funcione de forma correcta.

El script quedaría asi:

import Adafruit_DHT
import time

DATA_PIN = 3
SENSOR = Adafruit_DHT.DHT11

for i in range(0, 10):

    humidity, temperature = Adafruit_DHT.read_retry(SENSOR, DATA_PIN)

    if ((temperature != None)) and ((humidity != None)):
        print("Temperatura={0:0.1f}ºC | Humedad={1:0.1f}%HR".format(temperature, humidity, flush=True))
    else:
        print("Falla de lectura. Reintentando...", flush=True)

    time.sleep(5)

Una vez creado nuestro dockerfile y modificado el script, podemos crear la imagen.

    docker build -t rpi_dht11_sensor:v1 .

Creada la imagen, procedemos a probarla dentro de un contenedor.

    docker container run --rm --privileged rpi_dht11_sensor:v1

Notese el parametro --privileged para que el contenedor pueda acceder a los dispositivos de la raspberry pi. Esto es necesario para poder utilizar los pines GPIO.
Existen dos formas basicamente de lograr esto. Una es eligiendo el dispositivo, reemplazando la sentencia --privileged por --devices /dev/gpiomem. Esta ultima forma es la mas recomendada para estos casos, ya que simplemente comparte con el contenedor el dispositivo fisico del host. Sin embargo, las limitaciones de la imagen base impidieron que la imagen final pueda acceder al archivo correspondiente a dicho dispositivo. /dev/gpiomem, incluso habiendo modificado los grupos del sistema y de la imagen como es debido. Concluimos que el problema puede deberse a que no utilizamos una imagen base con la arquitectura provista por raspbian, sino una basada en debian. El metodo de --privileged dió buenos resultados, funcionando de forma automatica. De todas formas, no es recomendable utilizar este parametro en un contenedor de forma general. Esto suele ser una tecnica insegura y una practica desaconsejada, ya que el contenedor correrá mas cerca del sistema operativo del host, perdiendo ciertas ventajas de seguridad propias de los contenedores. En nuestro caso, dado que nos encontramos en un ambiente controlado y cerrado, podemos darnos el lujo de utilizar el parametro --privileged.

Docker Privileged: https://phoenixnap.com/kb/docker-privileged

Pagina web del sensor con Flask version 2.0.2

4 de Diciembre:

Teniendo nuestro sensor funcionando, procedemos a crear una pagina web que muestre los datos del sensor. Para ello, utilizaremos la librería Flask.

Fask quick start: https://flask.palletsprojects.com/en/2.0.x/quickstart/

Flask Tutorial: https://pythonbasics.org/flask-tutorial-hello-world/

    pip3 install Flask

Luego, aplicamos algunas modificaciónes a nuestro script para que sea ejecutable como una aplicación web.

    nano dht11_sensor_test.py
# import the Flask class from the flask module
from flask import Flask, render_template
import Adafruit_DHT

DATA_PIN = 3
SENSOR = Adafruit_DHT.DHT11

# create the application object
app = Flask(__name__)

# use decorators to link the function to a url
@app.route('/')
def home():
    humidity, temperature = Adafruit_DHT.read_retry(SENSOR, DATA_PIN)

    if ((temperature != None)) and ((humidity != None)):
        return("Temperatura={0:0.1f}ºC | Humedad={1:0.1f}%HR".format(temperature, humidity))
    else:
        return("Falla de lectura. Reintentando...")

# start the server with the 'run()' method
if __name__ == '__main__':
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

Luego simplemente corremos el script.

    python3 dht11_sensor_test.py

Nos dirigimos a un navegador web y colocamos la dirección de nuestra pagina web.

    [ip_nodo_host]:5000

Servicio Flask en contenedores

5 de Diciembre:

Metemos nuestro nuevo script en una imagen de docker. Para ello, editamos un dockerfile.

    nano dockerfile
FROM arm32v7/python:3.7.12-buster

RUN apt-get update && apt-get install -y python3-pip=18.1-5 rpi.gpio=0.6.5-1

RUN python3 -m pip install --upgrade pip setuptools wheel

RUN pip3 install Adafruit_DHT==1.4.0 Flask==2.0.2

COPY flask_dht11_sensor_test.py ./

CMD [ "python3", "flask_dht11_sensor_test.py" ]

Luego, creamos la imagen.

    docker build -t flask_dht11:v1 .

Una vez terminada, corremos un contenedor en docker para probarla. En este caso, cambiaremos

docker container run --rm --privileged -p 4000:5000 flask_dht11:v1

Subiendo la imagen a docker hub

5 de Diciembre:

Docker hub: https://hub.docker.com/

Docker hub quickstart: https://docs.docker.com/docker-hub/

Docker Repositories: https://docs.docker.com/docker-hub/repos/

El tener la imagen creada por nosotros subida a un repositorio en docker hub, permite facilitar el proceso de deployment en otras plataformas, incluyendo el cluster en si.

Para ello, uno debe tener una cuenta en docker hub. Una vez creada, seleccionamos "Create Reopistory" y le damos un nombre. en nuestro caso, llamaremos a nuestro repositorio "flask-dht11-rpi".

A continuación, cambiamos el tag de la imagen creada por uno que posea todas las caracteristicas estandar para el repositorio.

    docker image tag imagen_fuente:tag_fuente nombre_de_usuario/nombre_repositorio:tag_destino

El tag puede ser el mismo que el tag de la imagen original, o puede ser uno nuevo. Por ejemplo, en nuestro caso, el comando quedaría

    docker image tag flask_dht11:v1 alcaolpg/flask-dht11-rpi:latest

Luego, iniciamos sesion y subimos el archivo a docker hub.

    docker login
    docker push nombre_de_usuario/nombre_repositorio:tag_destino

Al finalizar la carga, cerramos sesion.

    docker logout

Imagen subida a docker hub: https://hub.docker.com/repository/docker/alcaolpg/flask-dht11-rpi

Deployment en el cluster de kubernetes

6 de Diciembre:

Al momento de lanzar la aplicación en el cluster, es importante notar que existe un tipo de archivo de vital importancia para el proceso. Los archivos .yaml (Yet Another Markup Language o YAML Ain't Markup Language) son una forma de definir los servicios y los contenedores que se encuentran en el cluster de forma rapida y entendible.

What is YAML?: https://www.redhat.com/en/topics/automation/what-is-yaml

Understanding Kubernetes Objects: https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/

En nuestro caso, debemos crear un archivo de configuración de contenedores y otro de servicios. El de contenedores se encargará de crear las pods que contienen nuestra aplicación, con todas sus caracteristicas necesarias. El de servicios se encargará de definir un servicio que permita acceder a la aplicación desde el exterior. Al igual que con docker, es necesario que la capsula que contenga la aplicación funcione en modo privilegiado.

Pod Security Polices: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privileged

Kubernetes Privileged Pod Practical Example: https://www.golinuxcloud.com/kubernetes-privileged-pod-examples/

    nano sensor.yaml

Dentro del mismo, escribimos:

apiVersion: apps/v1 # Version de Kubernetes para este objeto
kind: Deployment # Tipo de objeto
metadata:
  name: sensor # Nombre del objeto
  namespace: default # Nombre del espacio de trabajo
spec:
  replicas: 1 # Cantidad de pods que se crearan
  selector:
    matchLabels:
      app: sensor # Nombre del contenedor para identificacion de la aplicacion
  template:
    metadata:
      labels:
        app: sensor # Nombre del contenedor
    spec:
      containers:
        - name: flask-dht11-rpi # Nombre de la aplicacion
          image: alcaolpg/flask-dht11-rpi:latest # Nombre de la imagen que debe buscarse en docker hub
          ports:
            - containerPort: 5000 # Puerto utilizado para comunicarse con la aplicacion
              protocol: TCP
          securityContext:
            privileged: true # Permite que el contenedor acceda a los dispositivos GPIO
      nodeSelector:
        dhtsensor: "yes" # Selecciona los nodos que poseen el dispositivo DHT11

Paremonos en la ultima sentencia de la seccion "nodeSelector". En nuestro caso, el sensor se encuentra conectado a una unica placa Raspberry Pi 3B+ mediante GPIO. Por lo tanto, si queremos que el sistema sea capaz de obtener información del sensor, debemos especificar que el nodo debe tener el dispositivo DHT11. Para ello, nos valemos de la posibilidad de usar etiquetas o labels para cada nodo.

Assigning pods to nodes: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/

How to use Node Selectors in Kubernetes: https://www.howtoforge.com/use-node-selectors-in-kubernetes/

Desde el nodo maestro, agregaremos una etiqueta para que el nodo seleccionado por el sistema sea el correcto.

    kubectl label node [nombre del nodo con el sensor] nombre_del_campo_label=label_a_usar

En nuestro caso, la sentencia anterior quedaría:

    kubectl label node worker1 dhtsensor=yes

Para comprobar la etiqueta, podemos usar el comando:

    kubectl get nodes --show-labels

Creada nuestra etiqueta, procedemos a lanzar la aplicacion en el cluster.

    kubectl apply -f sensor.yaml

Podemos ver los resultados en la consola de kubernetes.

    kubectl get pods -o wide

Para poder acceder a la aplicación, todavia debemos crear el servicio que se encargue de redireccionar las solicitudes del exterior al contenedor de la aplicación. Este tipo de servicio se llama "nodeport".

    nano sensor_nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: sensor-nodeport # Nombre del servicio
  namespace: default
spec:
  type: NodePort
  selector:
    app: sensor # Nombre del contenedor que identfica a la aplicacion
  ports:
    - port: 5000 # Puerto utilizado para comunicarse con la aplicacion
      targetPort: 5000 # Puerto del contenedor de la aplicacion
      nodePort: 30001 # Puerto utilizado para acceder al contenedor desde el exterior

Una vez que creamos el servicio, podemos lanzarlo en el cluster.

    kubectl apply -f sensor_nodeport.yaml

Podemos comprobar que el servicio esté corriendo utilizando:

        kubectl get services

Por ultimo, accedemos desde el exterior al contenedor de la aplicacion. Desde una computadora dentro de la misma red, accedemos utilizando la direccion ip de cualquier nodo del cluster desde un navegador web.

    http://[ip del nodo]:30001

En caso de querer eliminar el servicio o el contenedor, podemos hacerlo con los comandos:

    kubectl delete pod [nombre del contenedor]

    kubectl delete deployment [nombre del contenedor]

    kubectl delete service [nombre del servicio]

Removing data collector Docker container / Kubernetes pod: https://www.ibm.com/docs/en/cloud-paks/cp-management/2.3.x?topic=monitoring-removing-data-collector-docker-container-kubernetes-pod