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 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 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 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 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 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 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 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:
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:
sudo swapoff -a
Para deshabilitar la partición swap de manera permanente editaremos el archivo fstab
usando nano:
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
# /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).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / 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:
sudo apt install docker.io
Habilitaremos que Docker corra siempre que el sistema se reinicie usando el comando:
sudo systemctl enable --now docker
Finalmente habilitaremos que Docker se ejecute sin necesidad de correr el comando sudo de super administrador usando el comando:
sudo usermod -aG docker TU_USUARIO
Ahora reiniciamos nuestra máquina virtual de Ubuntu Server usando el comando:
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:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl -–system
Para este tutorial estamos considerando que el firewall de Ubuntu Server está deshabilitado, en caso de requerir instalar un cluster con el firewall habilitado es necesario abrir los puertos TCP 6443, 2379, 2380, 10250, 10251 y 10252 en el nodo maestro y los puertos 10250 y del 30000 al 32767 en los nodos trabajadores.
Ahora para poder instalar las herramientas de nuestro cluster de Kubernetes instalaremos kubelet, kubeadm y kubectl usando las siguientes líneas de comandos:
sudo apt update && sudo apt install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Ahora iniciaremos nuestro cluster de Kubernetes usando la siguiente línea de comandos:
sudo kubeadm init
IMPORTANTE: Se puede agregar el parámetro --pod-network-cidr
agregando un bloque de direcciones IP el cuál queremos que sea utilizado para que nuestros Pods se comuniquen internamente en nuestro cluster, por default Kubernetes usa el bloque de direcciones IPv4 192.168.0.0/16
Una vez que se inicialice nuestro nodo maestro de Kubernetes vamos a habilitar que los comando que ejecutemos a través de kubeadm
no requieran usar sudo, utilizando los siguientes comandos:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Para que nuestros Pods se puedan comunicar dentro de nuestro cluster de Kubernetes es importante instalar el add-on de red que queremos utilizar en nuestro cluster, mi recomendación si no se tiene un requerimiento específico es instalar el add-on de Calico, pero también se tienen otras opciones, el add-on de red de Calico lo pueden encontrar en calico.yaml
y lo pueden aplicar al cluster usando el comando:
sudo kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml
O si reiniciaron el nodo después de quitar la restricción a kubeadm
usando el comando:
kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml
IMPORTANTE: Si se decidió utilizar otro bloque de direcciones IPv4 para los Pods es importante descargar antes el script calico.yaml
y modificar el bloque de direcciones a través del parámetro con nombre CALICO_IPV4POOL_CIDR
cambiándolo por el bloque de direcciones IPv4 que utilizamos inicializando el nodo maestro.
Para este tutorial permitiremos que el nodo maestro pueda ejecutar Pods, sin embargo, se recomienda que en producción no se aplique la siguiente línea de comandos por temas de seguridad:
kubectl taint nodes --all node-role.kubernetes.io/master-
En este momento nuestro nodo maestro de Kubernetes debería de estár corriendo sin problemas, para poder agregar más nodos a nuestro cluster es necesario tener a la mano el token válido generado por nuestro nodo maestro y el hash válido para establecer una relación de confianza con este nodo, para obtener el token usamos el comando:
kubeadm token create
Y para obtener el hash usaremos el comando:
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/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:
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:
sudo swapoff -a
Para deshabilitar la partición swap de manera permanente editaremos el archivo fstab
usando nano:
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
# /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).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / 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:
sudo apt install docker.io
Habilitaremos que Docker corra siempre que el sistema se reinicie usando el comando:
sudo systemctl enable --now docker
Finalmente habilitaremos que Docker se ejecute sin necesidad de correr el comando sudo de super administrador usando el comando:
sudo usermod -aG docker TU_USUARIO
Ahora reiniciamos nuestra máquina virtual de Ubuntu Server usando el comando:
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:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl –-system
Ahora para poder instalar las herramientas de nuestro cluster de Kubernetes instalaremos kubelet, kubeadm y kubectl usando las siguientes líneas de comandos:
sudo apt update && sudo apt install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Donde en los parámetros:
<token>
se tendrá que cambiar por el toquen que generamos en la sección anterior.<control-plane-host>
se usará la dirección IP que tiene el nodo maestro de Kubernetes.<control-plane-port>
se usará el puerto TCP 6443 definido por default en Kubernetes.<hash>
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:
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 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:
kubectl create deployment nginx --image=nginx
Para revisar que nuestro pod se creó podemos usar el comando:
kubectl get pods
Ahora revisaremos el status del ReplicaSet que controla a éste pod usando el comando:
kubectl get replicasets
Finalmente revisamos el status de nuestro deployment usando el comando:
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
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
externalIPs:
<kubernetes-master-ip>
Donde <kubernetes-master-ip>
contendrá la dirección IP de tu nodo maestro de Kubernetes, para poder aplicar el nuestro nuevo Servicio en Kubernetes, usamos el comando:
kubectl apply -f myservice.yaml
Nos aseguramos que nuestro servicio esté corriendo usando el comando:
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 <kubernetes-master-ip>
Ahora si quisiéramos incrementar la cantidad de Pods en nuestro deployment podemos utilizar el comando:
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 <kubernetes-master-ip>
Para poder revisar la cantidad de Pods que existen en nuestro cluster o están en proceso de creación usamos el comando:
kubectl get pods
Podemos corroborar que existen ahora 5 pods con NGINX ejecutándose, de igual manera podemos revisar el ReplicaSet usando el comando:
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:
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 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.