lunes, 25 de mayo de 2020

Kubernetes para principiantes

Bueno, ya vimos Ansible, ya vimos Docker y ahora vamos con Kubernetes.
No, hoy no te voy a hacer el chiste del hacker, aunque si, me sigue causando gracia.
Hoy vamos al grano, porque es un post largo que creo que les va a resultar útil.

Kubernetes (K8s) es un proyecto open source que nació en Google y sirve para orquestar contenedores (Docker), aunque no nos permite crear imágenes, ni subirlas al registry, solo sirve para gestionarlos. Es un buen complemento, sino el ideal, de Docker (motor de contenedores) para los entornos de producción grandes en donde Docker solo, no puede escalar.
Distribuye de la mejor forma posible la carga de todos los NODOS.

POD: La unidad mas chica en Kubernetes es un POD, que agrupa dentro suyo diferentes contenedores (en general uno solo) que tienen un componente (kubelet) "que le avisa" al NODO MASTER si la aplicación se encuentra o no corriendo. Y si no esta corriendo entonces Kubernetes levanta una nueva para mantener la cantidad de replicas que configuramos para que se encuentren corriendo. Estas instancias se levantan en base a una imagen, como los containers de Docker.
Los PODs por definición son stateless, y Kubernetes los crea o destruye de manera constante en función de las necesidades. Si los PODs deben tener datos persistentes, deben utilizarse volúmenes.
Los containers levantados en el mismo POD comparten el stack de red y pueden hablar entre si, así como también pueden compartir un volumen y acceder a la misma información. Cada POD tiene su propia direccion IP.
La desventaja de que los containers dentro del POD compartan el stack de red es que no podes tener 2 containers adentro del mismo POD escuchando en el mismo puerto, porque al tener la misma red hay colisión de puertos, pero esto se resuelve poniendo esos 2 containers en PODs diferentes.

NODO: Un NODO conjunto de PODs.

NODO MASTER: Se encargan de coordinar el clúster. Tiene que haber mínimo uno por cluster. Generalmente no ejecutan contenedores, sino que deciden en qué nodo se ejecuta cada contenedor. Usualmente son 3 nodos para alta disponibilidad. Esto es debido a etcd, que guarda el estado global del clúster y su información es crítica. Si hay 3 nodos de etcd y se pierde uno, el sistema puede seguir funcionando, ya que los dos nodos restantes pueden seguir verificándose el uno al otro. Pero ya no se puede perder ningún otro. Por eso, los nodos de etcd se escalan siempre de dos en dos, si hay 3 se puede perder 1, si hay 5 se pueden perder 2 y así sucesivamente.

El NODO MASTER ejecuta los siguientes procesos:
- kube-apiserver que es la forma en la que interactuamos con los otros NODOS del cluster.
- Kubernetes Controller (kube-controller) que compara el estado actual del cluster con el estado que debería tener (chequea por ejemplo si la cantidad de PODs que hay en un NODO es la que debería haber, y sino los levanta).
- Kubernetes Scheduler (kube-scheduler) que es el que se encarga de escuchar al controller y cuando el controller le avisa que le faltan PODs, el scheduler se fija en que NODO pueden estar mejor ubicados y los levanta ahí.
- etcd que es una base de datos que se utiliza para mantener la configuración global del clúster. La información contenida en etcd es crítica y debe tenerse siempre un plan de copias de seguridad.

NODO MINION (WORKERS): Se encargan de la ejecución de los contenedores desplegados en el clúster. Tienen instalado el agente de Kubernetes llamado kubelet (que se encarga de monitorizar que un contenedor se inicie, funcione correctamente y en caso de error, reiniciarlo inmediatamente) y un kube-proxy, que gestiona la red virtual y las IPs virtuales que de cada contenedor.

CLUSTER: Es un conjunto de NODOS.
Entre sus principales funciones se encuentran:
. Permite Escalar
. Permite balanceo de carga
. Reparación automática del contenedor (si falla o muere, el cluster automáticamente levanta uno nuevo)
. Distribución inteligente de la carga de trabajo
. Permite almacenamiento persistente en la nube
. Optimiza nuestros recursos
Para entornos de Workstation se puede usar Minikube .

SERVICES: Los PODs no son visibles más allá de su propio contenedor. Para solucionar esto, existen los services, que son objetos que permiten reenviar tráfico de red a un conjunto de PODs, lo cual nos permite acceder a nuestras aplicaciones. Los services utilizan servidores DNS instalados en la red para registrarse en esta y permitir el acceso por nombres de servicio a sus PODs, facilitando el descubrimiento de los mismos.

VOLUMENES PERSISTENTES: Es una pieza de almacenamiento en el cluster que sirve para guardar los datos de nuestros PODs. Su ciclo de vida es independiente de los PODs individuales.

LABELS/SELECTORS: Los selectors son filtros de las etiquetas. Las labels son muy útiles cuando por ejemplo manejamos 500 contenedores que hacen de webserver y cuya etiqueta es webserver, entonces, si queremos eliminarlos a todos ponemos que borre todo lo que tenga esa etiqueta en lugar de borrar uno por uno.

En Kubernetes, podemos exponer nuestras aplicaciones de varias maneras:
ClusterIP, es el servicio que se genera de forma predeterminada y nos permite acceder a los servicios dentro del clúster. Este servicio no es accesible desde Internet, para que lo sea necesitaríamos habilitar el acceso a través del proxy de Kubernetes.
- Usando un servicio de tipo Kubernetes NodePort, que expone la aplicación en un puerto a través de cada uno de sus nodos. Sólo un servicio por puerto. No es para ambientes en Producción.
- Usando un servicio de tipo Kubernetes LoadBalancer, que crea un balanceador de carga externo que apunta a un servicio Kubernetes en su clúster.
- Usando un Kubernetes Ingress Controller, que permite un enrutamiento HTTP basado en host o URL. Ingress no es un tipo de servicio como el resto, se trata más de un enrutador que permite la entrada al clúster y gestionar el acceso a múltiples servicios. Hay que tener en cuenta que un Ingress Controller generalmente no elimina la necesidad de un LoadBalancer externo: el Ingress Controller solo agrega una capa adicional de enrutamiento y control detrás del balanceador de carga.
Estos son los patrones básicos para enrutar el tráfico externo a su clúster Kubernetes.

MINIKUBE: Es un proyecto que nos permite probar Kubernetes en una maquina local y utiliza maquinas virtuales de Virtual Box (por defecto). Kubernetes necesita al menos 3 nodos para funcionar, lo cual no siempre es posible en una maquina local. Para eso se creó Minikube, que es una versión reducida de Kubernetes, que corre en una única máquina virtual que hace de maestro y esclavo a la vez.
Ademas de Minikube también necesitara instalar kubectl para poder comunicarse con el servidor Kubernetes.

Kubernetes tiene también una parte Web, con un dashboard que permite monitorizar y gestionar el clúster. Minikube viene instalado con uno por defecto.

DEPLOYMENT: Para mantener los PODs prestando servicio sin interrupción utilizamos los deployments, acá definimos cuantas replicas queremos, como queremos desplegarlos, como queremos escalar y Kubernetes se encarga de mantener el clúster funcionando. Los deployments crean replication controllers que por defecto mantienen el número de réplicas que especificamos en el despliegue, pero nos permitirán cambiar este numero a futuro si así lo deseamos.

Bueno, hasta acá toda la teoría, pero estas aburrido, ¿no?
Queres tocar, queres poner manos a la obra, queres revolcarte en este chiquero (?).
Empecemos:


Instalar Minikube:

sudo curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64

sudo chmod +x minikube


Iniciar Minikube:

sudo mv minikube /usr/local/bin
DOCKER_HOST=ssh://usuario@host
minikube start


(Esto demora algunos minutos porque tiene que crear la maquina virtual)

Instalación finalizada
Podes constatar la creación de la maquina en Virtual Box:

Vemos que creo la virtual y que se encuentra corriendo
Bueno particularmente yo tuve algunos problemas para la instalación. Lo que hay que tener en cuenta para usar Minikube son 3 cosas: la primera es que necesitas tener instalado Docker (acá hay un post que hice de como instalarlo), la segunda es que tenes que tener instalado Virtual Box (o algún software de virtualización para que Minikube pueda crear la maquina virtual) y la tercera, es que si estas probando en una maquina virtual vas a tener que tener un procesador que te permita la virtualizacion anidada.

Entonces:

Para instalar Docker entras acá.

Para instalar Virtual Box seguís estos pasos:

Primero agregas a /etc/apt/sources.list el repo para tu versión de Debian del hypervisor que vas a instalar, en este caso será VirtualBox y Buster (Debian 10):

deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian buster contrib

Descargamos las keys y las agregamos:

wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -

wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -

Actualizamos repositorios y procedemos con la instalación de VirtualBox:

sudo apt-get update
sudo apt-get install virtualbox-6.1

La instalación en Ubuntu 20.04 la haces directo de los repos:

sudo apt-get install virtualbox

******************** Si no te dio error podes saltear esta parte ********************
******************************************************************************************
Separo esta parte del post porque tiene que ver con algunos errores particulares que tuve durante la instalación de Virtual Box en Debian 10:

Primero error de dependencias:


Para arreglarlo:

sudo apt --fix-broken install

Luego, si al ejecutar Minikube start te da el siguiente error (WARNING: The vboxdrv kernel module is not loaded):


Ejecutas:

sudo /sbin/vboxconfig

Para este otro error (Failed to start virtualbox VM. "minikube start" may fix it: creating host: create: precreate: This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory) tenes que ir primero al BIOS para habilitar la virtualizacion y luego, en la maquina virtual hay que habilitar lo siguiente:



Por ultimo, 2 cositas mas, si tenes que habilitar la virtualizacion anidada en ESXi podes seguir estos pasos, básicamente lo que hay que hacer es agregar la linea vhv.enable = "TRUE" en el vmx de la virtual.
Y lo otro, si usas Debian 10 y el kernel 4.19.0-5-amd64 no encontré la forma de que funcione Virtual Box (ni que cargue el modulo). Al parecer, le pasa a mucha gente, haciendo incluso que muchos pasen de Buster a Stretch donde aparentemente no se presenta el problema.

Hasta acá el segmento de errores (a nadie le da error la instalación ¬¬).

*******************************************************************************************
*******************************************************************************************
Iniciar Dashboard Minikube:

minikube dashboard



Instalar cliente de Kubernetes (kubectl) para poder interactuar con el cluster:

Descargar cliente kubectl:

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl

Otorgar permisos de ejecución:

sudo chmod +x ./kubectl

Mover binario a /usr/local/bin para que esté disponible:

sudo mv ./kubectl /usr/local/bin/kubectl

Comprobar que la versión este actualizada:

kubectl version --client


Ver la versión de Kubernetes:

kubectl version

Ver los pods del cluster:

kubectl get pods

Ver listado de nodos del cluster:

kubectl get nodes

Solo nos aparece el Nodo Master, que es la virtual con Minikube
Para mas detalle de los nodos:

kubectl describe nodes

Ver log de POD: 

kubectl logs nombredelpod

Borrar POD:

kubectl delete pod nombredelpod

Despliegue de contenedores:
Vamos a desplegar uno usando la imagen de Apache httpd:latest del hub de Docker

kubectl create deployment hello-http --image=httpd:latest

hello-http es el nombre del despliegue.

Ver estado de nuestro despliegue:

kubectl get pods

Aparece el hello-http que acabamos de desplegar
Ver detalle de nuestro despliegue:

kubectl describe pod hello-http


Desplegamos un POD con los contenedores descritos en el archivo webapp.yml:

kubectl apply -f webapp.yml

Con apply si no existe el objeto lo crea, y si existe lo actualiza.

WEBAPP.YML
---
apiVersion: v1 #Version del archivo

kind: Pod #Esta aplicacion se va a desplegar en un unico POD

metadata:
  name: mi-app #Nombre de mi aplicacion
  labels:
    app: web #Etiqueta

spec:
  containers: #Defino los contenedores que me va a desplegar
    - name: front-end #Nombre del contenedor
      image: nginx #Nombre de la imagen a partir de la cual se despliega el contenedor
      ports:
        - containerPort: 80 #Puerto por el que escucha

    - name: back-end #Nombre del segundo contenedor del POD
      image: redis #Nombre de la imagen (base de datos). ACA hay mas info de la imagen

Los despliegues solo son visibles dentro de nuestro cluster, si queremos que sean visibles fuera de él tenemos que exponer el servicio:

kubectl expose deployment hello-http --type=LoadBalancer --port=80

Acá le estamos diciendo a Kubernetes que exponga el puerto 80 del servicio 'hello-http' usando balanceo de carga (generalmente round robin).

Ver servicios desplegados:

kubectl get services


Nos muestra el nuevo servicio expuesto hello-http con su IP dentro del cluster y una IP externa, que como estamos usando Minikube no nos la dará. Para tener una IP externa deberíamos usar un cluster real on premise o algún servicio de Cloud como el de Google, Microsoft (Azure) o Amazon (AWS).
Luego vemos que mapea el puerto 80 de nuestro contenedor con el 32319 del servidor publico que es el que nos da el servicio externo.

Ok, ¿y como accedo desde el navegador? Ejecutando este comando nos va a dar la URL:

minikube service hello-http --url


En mi caso: http://192.168.99.100:32648  
Si coloco la ip y el puerto en mi navegador puedo ver que esta funcionando:

También podes hacer la prueba desde la misma terminal en caso de que no tengas interfaz gráfica con:

curl http://192.168.99.100:32648  

Aparece It works!
O con Lynx, el navegador de terminal así:

lynx http://192.168.99.100:32648 


Incluso, podrías usar mi posteo de Squid, instalarlo en la maquina que esta corriendo el Minikube, y luego en otra maquina de la red, por ejemplo con Windows, podrías acceder al POD desde un navegador con el proxy de la maquina con Minikube configurado:


No lo podes crees, estás anonadado.Ya sé, pero sigamos.

En webapp.yml cambie el deployment por el siguiente:

apiVersion: apps/v1 
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # Cantidad de pods
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:

        - containerPort: 80

Como esto seria una nueva versión de la aplicación vuelvo a ejecutar el deployment para que se actualice:

kubectl apply -f webapp.yml

Lo que hace Kubernetes es levantarme un nuevo POD con la nueva versión, cuando queda disponible, baja uno de los viejos, y así hasta que me queda solamente la cantidad de PODs que configuramos (las replicas) todos con la nueva versión.

En este momento estamos corriendo 2 PODs con nginx, como indica el archivo webapp.yml en la parte de cantidad de replicas:


Ahora voy a cambiar en el archivo, la cantidad de replicas a 5. Ejecuto de nuevo el deployment:

kubectl apply -f webapp.yml

Y verifico la cantidad de PODs:

kubectl get pods


Vemos que hay 5 con nginx. Para que se vea con mas claridad vamos a hacer lo siguiente:

Verificamos la cantidad de PODs con nginx (hay 5):

kubectl get pods

Matamos uno de los PODs (uno de los 2 que lleva 9 minutos corriendo):

kubectl delete pod nginx-deployment-5bf87f5f59-48svz

Verificamos nuevamente a ver si volvió a levantar el POD que matamos para completar los 5:

kubectl get pods


En la imagen podemos ver que de los 2 PODs que había con 9 minutos, quedo uno, y hay uno nuevo que lleva apenas 4 segundos levantado. Esto lo hizo en menos de lo que tarde en volver a ejecutar el comando para ver los PODs (que básicamente es flechita para arriba y enter).

Bueno, mas o menos esta es la idea de lo que debería suceder en un cluster.
Ya son administradores de Kubernetes, ponganlo en Linkedin ¬¬

Antes de finalizar sigamos con algunos comandos mas:

Ver namespaces:

kubectl get ns

Ver servicios de un namespaces en particular (sino muestra el por defecto):

kubectl -n nombredelnamespace get services


Escalar Servicios:
Podemos escalar el numero de PODs con un simple comando:

kubectl scale deployment --replicas=10 hello-http

En este caso desplegamos 10 PODs con el servicio hello-http. Este numero de replicas Kubernetes lo mantendrá todo el tiempo, es decir, si se cuelga o muere algún POD levantara uno nuevo para mantener ese numero.


Podemos cambiar el escalado a 3 PODs por ejemplo:

kubectl scale deployment --replicas=3 hello-http


Vemos como algunos de los 10 PODs hello-http comienzan a finalizarse
Y si ejecutamos rápidamente kubectl get pods podemos ver como va terminando los PODs que teníamos para llegar a 3 que es el nuevo numero de replicas que configuramos.

Vemos como solo quedaron 3 PODs hello-http
Eliminar POD:

kubectl delete pod nombredelpod

Eliminar despliegue de la imagen nginx-deployment:

kubectl delete deployment nginx-deployment



Eliminar despliegue del archivo webapp.yml:

kubectl delete -f webapp.yml

Eliminar servicio expuesto hello-http:

kubectl delete service hello-http

Verificamos con: 

kubectl get services


Para ver un listado de lo que tenemos corriendo en el cluster (PODs, NODOS, Deployments y Services):

kubectl get all


Eliminar Minikube:

minikube delete

KUBERNETES EN LA NUBE:

No probé estos comandos (todo lo anterior si), con lo cual no estoy seguro si funcionan.
Si alguno lo hizo y quiere compartir los comandos probados en los comentarios bienvenido.

Azure -> AKS (Azure Kubernetes Service)

Para crear cluster:

az login

az account set --subscription "NombreSuscripcion"

az group create --name aks-resource-group --location eastus

az aks create --name aks-cluster --resource-group aks-resource-group --node-count 3 --generate-ssh-keys

sudo az aks install-cli

az aks get-credentials --name aks-cluster --resource-group aks-resource-group

Google -> GKE (Google Kubernetes Engine)

Para crear cluster:

gcloud config set project IDdelProyecto

gcloud container clusters create [CLUSTER_NAME] \
        --zone [COMPUTE_ZONE]

gcloud containers clusters get-credentials NombreCluster

AWS -> EKS (Elastic Kubernetes Service)

Para crear cluster:

eksctl create cluster --name=eksworkshop-eksctl --nodes=3 --node-ami=auto --region=${WAS_REGION}

o

eksctl create cluster --name my-cluster --without-nodegroup

La API de Kubernetes es común en todos los proveedores.
Estos proveedores ofertan un servicio autogestionado, aunque en el caso de AWS los nodos MASTER los gestionan ellos, pero los WORKERS no, tenes que crearlos, provisionarlos y gestionarlos vos.

Bueno, esto ha sido todo por hoy. Creo que para una introducción a Kubernetes o para un Kubernetes para principiantes está bien, ¿no?
Espero que les haya sido útil, y si ven algún error, sugerencia u otra cosa pueden dejarlo en los comentarios.
Nos vemos la próxima!
Y por si no nos vemos, buenos días, buenas tardes y buenas noches.

COMPATÍ, ¿que esperas?

PD: Me llamó Ramon, por el post de la vez pasada, quedó contento, su esposa y sus hijos nunca vieron la información confidencial que estaba frente a sus ojos :)

No hay comentarios:

Publicar un comentario