kubernetes containers docker orchestration Tutorial: ¿Cómo instalar tu primer Cluster de Kubernetes? Kubernetes te permite orquestar tus containers de manera muy sencilla Rafael Escalante · May 10, 2020 **Kubernetes** es un sistema orquestador de **containers** que permite realizar el despliegue de containers de manera automática y ordenada, lo que permite a los desarrolladores a desplegar aplicaciones basadas en containers de manera ágil y segura. En este tutorial definiremos los conceptos básicos que se utilizan en Kubernetes , definiremos lo que es un container y cómo se puede desplegar en un sistema, finalmente instalaremos un cluster de Kubernetes. ## ¿Qué es un Container? Un **container** es un paquete de software que contiene los servicios esenciales para que la aplicación contenida en este paquete pueda funcionar de manera adecuada y sin necesidad de tener una dependencia directa en el sistema operativo, lo que los hace muy versátiles y livianos. Un container contiene exclusivamente los servicios necesarios para que la aplicación que se empaqueta pueda correr sin ningún problema y se pueda replicar de acuerdo a las necesidades del usuario. Por ejemplo, éste blog en [rescalante.com](https://rescalante.com) se puede **contenerizar** (tratando de traducir el término en Inglés conteinerize) solo con los servicios necesarios para que pueda correr éste blog (servicios web principalmente), en caso de que el blog llegue a tener demasiados usuarios conectados a la vez el sistema a través de un orquestador como **Kubernetes** puede replicar la aplicación de rescalante.com múltiples veces hasta soportar la demanda que se tiene (lo cuál incrementa los recursos de procesamiento), después de que la demanda baja, el sistema decida eliminar los containers que fueron creados para soportar la demanda y a su vez los recursos disminuirán. Ahora consideremos el ejemplo anterior en un entorno de nube, una empresa que tenga por ejemplo una tienda en línea puede contenerizar su aplicación para que pague solo por los recursos que estén asociados a las conexiones a la tienda, por lo que pagará el mantenimiento de recursos de hardware de acuerdo a la demanda que tenga. ## ¿Por qué Kubernetes? Para poder crear containers existen herramientas como [Docker](https://www.docker.com/) las cuáles a través de scripts permiten a los programadores crear containers o aplicaciones basadas en varios containers, sin embargo, ¿cómo podemos manejar varios containers a la vez?, o ¿cómo a través de un cluster en un **Data Center** podemos orquestar múltiples aplicaciones optimizando recursos al máximo?, es por eso que Kubernetes tiene suma importancia permitiendo a múltiples nodos de hardware mantener múltiples aplicaciones basadas en containers en tiempo real. [Kubernetes](https://kubernetes.io/es/docs/concepts/overview/what-is-kubernetes/) para poder funcionar requiere de un nodo maestro y la cantidad de nodos esclavos que el usuario defina, es importante que se defina a un nodo como un conjunto de recursos de Hardware, para este tutorial utilizaremos Máquinas Virtuales que representaran a nuestros recursos de Hardware en un Data Center. Antes de empezar a instalar nuestro primer cluster de Kubernetes es importante que definamos los objetos básicos que podemos crear en nuestro cluster, este tutorial no tiene el objetivo de convertirnos en expertos en Kubernetes pero si de entender los conceptos básicos y poder probar el orquestador. ## ¿Qué es un Pod? Un [Pod](https://kubernetes.io/es/docs/concepts/workloads/pods/pod/) es el objeto más pequeño y básico desplegable en Kubernetes, es una unidad básica de ejecución que representa procesos corriendo en nuestro cluster. Un **pod** tiene la función de encapsular un container (o en algunos casos múltiples containers), recursos de almacenamiento, una dirección IP única que es válida solo dentro de nuestro cluster y las opciones que definen como el container debe ejecutarse. Para fines prácticos un Pod puede ser la definición lógica de un Container en Kubernetes. Los pods tiene un ciclo de vida definido por un **Deployment** y un **ReplicaSet**, los pods vivirán de acuerdo a las necesidades que se definan en un **Deployment** en nuestro cluster y serán forzados a vivir o morir de acuerdo a la definición del ReplicaSet. ## ¿Qué es un ReplicaSet? Un [ReplicaSet](https://kubernetes.io/es/docs/concepts/workloads/controllers/replicaset/) es una regla definida mediante un Deployment en Kubernetes y usuados para garantizar la disponibilidad de un número específico de Pods idénticos. Si lo que queremos entender de manera más sencilla el ReplicaSet es el teniente de un grupo de soldados razos que son los Pods y lo obedecerán con los ojos cerrados incluso si tienen que morir. ## ¿Qué es un Deployment? Un [Deployment](https://kubernetes.io/es/docs/concepts/workloads/controllers/deployment/) es un conjunto de ordenes declaradas que se le dan a nuestro cluster de Kubernetes todos los ReplicaSets y los Pods se alinean a lo que diga un Deployment, por ejemplo, un Deployment de una aplicación web puede decirle a un ReplicaSet cuántos Pods se requieren para mantener la demanda de esta aplicación bajo ciertas circunstancias, por ejemplo, un Deployment puede definir que cuando la aplicación web tenga más de 5000 requests simultáneos, envíe una orden al ReplicaSet para aumentar los Pods de 5 a 10, y esos Pods se distribuirán en el cluster de Kubernetes donde haya recursos de Hardware disponibles, cuando los requests a nuestra aplicación disminuyan la orden del Deployment puede ser que la cantidad de Pods requeridos ahora son 5 por lo que los 5 pods que se generaron para cubrir la demanda tendrán que morir de acuerdo a las ordenes asignadas y forzadas por el ReplicaSet. ## ¿Qué es un Servicio? Un [Service](https://kubernetes.io/es/docs/concepts/services-networking/service/) o **Servicio** es un manera abstracta de exponer la aplicación definida en el Deployment como un grupo de Pods como un Network Service o Servicio de Red, vaya, un servicio es la manera que las aplicaciones que viven en nuestro cluster de Kubernetes se presentan al mundo exterior, por ejemplo, yo puedo presentar una aplicación web que está respaldada por 20 Pods a través de un Servicio al mundo exterior usando una dirección IP la cuál servirá como el punto de contacto para llegar a los 20 Pods, es importante mencionar que gracias a los Servicios es que los usuarios no nos damos cuenta si estamos enviando un request al Pod número 1 o al Pod número 12 ya que para nosotros es totalmente transparente y solo nos conectamos a una dirección IP que contiene la aplicación web. Seguramente cuando ustedes realizan una compra en línea, esa transacción se está ejecutando en algún Pod en alguna parte del mundo con los recursos disponibles. ## Nuestro primer cluster de Kubernetes. Ahora que ya definimos las unidades básicas en **Kubernetes** procederemos con la instalación de nuestro primer cluster, para realizar esta instalación es necesario tener a al menos dos máquinas virtuales con: * Ubuntu Server 18.04 LTS o 20.04 LTS. * 2 vCPUs. * 2 GB RAM. * Dirección IP disponible en tu red local. La **prima máquina virtual** la llamaremos `master-vm` y fungirá como nuestro nodo maestro para poder instalar Kubernetes, la segunda máquina virtual la llamaremos `minion1-vm` que será nuestro primer nodo trabajador para correr Pods en nuestro clúster (si ustedes quieren utilizar más máquinas virtuales simplemente las pueden ir nombran como `minion2-vm` y así subsecuentemente. ## Instalación del Master Node de Kubernetes. Vamos a conectarnos a la línea de comandos de nuestra primera máquina virtual y correremos los comandos para actualizar **Ubuntu Server**: ```sh sudo apt update && sudo apt upgrade -y ``` Ahora de acuerdo a uno de los requerimientos de **Kubernetes** es importante que se deshabilite la partición swap de Ubuntu, esto se puede realizar mediante el comando: ```sh sudo swapoff -a ``` Para deshabilitar la partición swap de manera permanente editaremos el archivo `fstab` usando nano: ```sh sudo nano /etc/fstab ``` Y agregaremos el carácter # al inicio de la línea `/swap.img none swap sw 0 0` quedando el archivo `fstab` de la siguiente forma: ``` fstab ``` ```sh # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # # / was on /dev/sda2 during curtin installation /dev/disk/by-uuid/6b043bc0-71d5-4de8-93ce-09d7eb21eaa0 / ext4 defaults 0 0 #/swap.img none swap sw 0 0 ``` Para poder instalar **Kubernetes** es importante que tengamos una herramienta que ejecute containers, para ello instalaremos **Docker** usando la siguiente línea de comandos: ```sh sudo apt install docker.io ``` Habilitaremos que **Docker** corra siempre que el sistema se reinicie usando el comando: ```sh sudo systemctl enable --now docker ``` Finalmente habilitaremos que **Docker** se ejecute sin necesidad de correr el comando sudo de super administrador usando el comando: ```sh sudo usermod -aG docker TU_USUARIO ``` Ahora reiniciamos nuestra máquina virtual de **Ubuntu Server** usando el comando: ```sh sudo reboot ``` Una vez que se reinicie la máquina virtual iniciaremos la instalación del nodo maestro de **Kubernetes**, un requerimiento importante es que la tabla de direcciones IP puedan ver el tráfico que viene en modo bridge, esto es para que las redes internas de **Kubernetes** puedan routear la información con nuestra interface de Ubuntu, para ello usaremos los siguientes comandos: ```sh cat </dev/null | openssl dgst -sha256 -hex | sed 's/^.*' ``` Es importante tener a la mano el **token** y el **hash** generado por nuestro nodo maestro ya que lo usaremos en la siguiente sección. ## Instalación de un Minion Node en Kubernetes. Vamos a conectarnos a la línea de comandos de nuestra máquina virtual que representa al nodo trabajado, primero correremos los comandos para actualizar Ubuntu Server: ```sh sudo apt update && sudo apt upgrade -y ``` Ahora de acuerdo a uno de los requerimientos de **Kubernetes** es importante que se deshabilite la partición swap de Ubuntu, esto se puede realizar mediante el comando: ```sh sudo swapoff -a ``` Para deshabilitar la partición swap de manera permanente editaremos el archivo `fstab` usando nano: ```sh sudo nano /etc/fstab ``` Y agregaremos el carácter # al inicio de la línea `/swap.img none swap sw 0 0` quedando el archivo `fstab` de la siguiente formha: ``` fstab ``` ```sh # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # # / was on /dev/sda2 during curtin installation /dev/disk/by-uuid/6b043bc0-71d5-4de8-93ce-09d7eb21eaa0 / ext4 defaults 0 0 #/swap.img none swap sw 0 0 ``` Para poder instalar **Kubernetes** es importante que tengamos una herramienta que ejecute **containers**, para ello instalaremos **Docker** usando la siguiente línea de comandos: ```sh sudo apt install docker.io ``` Habilitaremos que **Docker** corra siempre que el sistema se reinicie usando el comando: ```sh sudo systemctl enable --now docker ``` Finalmente habilitaremos que **Docker** se ejecute sin necesidad de correr el comando sudo de super administrador usando el comando: ```sh sudo usermod -aG docker TU_USUARIO ``` Ahora reiniciamos nuestra máquina virtual de **Ubuntu Server** usando el comando: ```sh sudo reboot ``` Una vez que se reinicie la máquina virtual iniciaremos la instalación del nodo maestro de **Kubernetes**, un requerimiento importante es que la tabla de direcciones IP puedan ver el tráfico que viene en modo bridge, esto es para que las redes internas de **Kubernetes** puedan routear la información con nuestra interface de Ubuntu, para ello usaremos los siguientes comandos: ```sh cat <` se tendrá que cambiar por el toquen que generamos en la sección anterior. * `` se usará la dirección IP que tiene el nodo maestro de Kubernetes. * `` se usará el puerto TCP **6443** definido por default en Kubernetes. * `` se usará el hash que generamos en la sección anterior. Después de unos minutos en el **nodo maestro** de **Kubernetes** ejecutaremos el comando: ```sh kubectl get nodes ``` Donde observaremos que tenemos nuestro **master node** y nuestro **minion node 1** reportando en nuestro cluster. A partir de este momento nuestro cluster está listo podemos empezar a hacer deployments de aplicaciones en **Kubernetes**. Este proceso se puede repetir para agregar más minions a nuestro cluster de **Kubernetes**. ## Probando nuestro Cluster de Kubernetes desplegando NGINX. [NGINX](https://nginx.org/) es un servidor web liviano que se encuentra contenerizado y fácilmente se puede probar con Docker, en este tutorial desplegaremos una aplicación basada en el container **NGINX**, desplegaremos **5 Pods** en nuestro cluster y a través de un **Servicio** publicaremos la aplicación para que sea visible desde la dirección IP del master node en el puerto TCP **80** que es el puerto default que utilizan los navegadores web. Para realizar el despliegue de **NGINX** desde nuestro **master node** ejecutaremos la siguiente línea de comandos para colocar un Deployment en nuestro cluster de un **Pod** usando como base el container de NGINX: ```sh kubectl create deployment nginx --image=nginx ``` Para revisar que nuestro pod se creó podemos usar el comando: ```sh kubectl get pods ``` Ahora revisaremos el status del **ReplicaSet** que controla a éste pod usando el comando: ```sh kubectl get replicasets ``` Finalmente revisamos el status de nuestro deployment usando el comando: ```sh kubectl get deployments ``` Ahora expondremos hacia la red nuestro deployment de nginx publicando un servicio, para ello definiremos nuestro nuevo servicio usando un archivo **.yaml** que lo llamaremos `myservice.yaml` y tendrá el siguiente contenido, se puede usar nano para crear el archivo: ``` myservice.yaml ``` ```sh apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - name: http protocol: TCP port: 80 targetPort: 80 externalIPs: ``` Donde `` contendrá la dirección IP de tu nodo maestro de Kubernetes, para poder aplicar el nuestro nuevo Servicio en Kubernetes, usamos el comando: ```sh kubectl apply -f myservice.yaml ``` Nos aseguramos que nuestro servicio esté corriendo usando el comando: ```sh kubectl get services ``` La exposición de nuestra aplicación de **NGINX** en servicio permitirá que puedas acceder al servidor de **NGINX** usando el puerto TCP **80** en el sitio `` Ahora si quisiéramos **incrementar** la cantidad de **Pods** en nuestro deployment podemos utilizar el comando: ```sh kubectl scale --current-replicas=1 --replicas=5 deployment/nginx ``` Ahora nuestra aplicación de **NGINX** usará **5 Pods**, lo que quiere decir que se están ejecutando 5 containers de NGINX en nuestro cluster y todos se acceden mediante el Servicio `nginx-service` que creamos a través de la dirección `` Para poder revisar la cantidad de **Pods** que existen en nuestro cluster o están en proceso de creación usamos el comando: ```sh kubectl get pods ``` Podemos corroborar que existen ahora **5 pods** con **NGINX** ejecutándose, de igual manera podemos revisar el **ReplicaSet** usando el comando: ```sh kubectl get replicasets ``` Y veremos que nuestro **ReplicaSet** está dando la orden de mantener **5 Pods de NGINX**, finalmente revisamos nuestro **Deployment** usando el comando: ```sh kubectl get deployments ``` Podemos revisar que el **Deployment** está pasando la orden al **ReplicaSet** de mantener **5 pods de NGINX** corriendo en nuestro cluster. [Kubernetes](https://kubernetes.io/es/docs/concepts/overview/what-is-kubernetes/) es un sistema de orquestación de containers que nos abre muchas posibilidades para el desarrollo de aplicaciones, espero que éste tutorial haya sido de tu agrado y por favor déjanos tus comentarios o recomendaciones al final de este post. #### Referencias: * [Docker](https://docker.com/) * [Kubernetes Setup](https://kubernetes.io/docs/setup/) * [Kubernetes kubectl Cheatsheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)