En los años 90, cuando apareció la WWW, los recursos se publicaban en internet subiendo los ficheros directamente a un servidor mediante FTP y, si aquel tenía todas las dependencias necesarias configuradas por el administrador de sistemas, la web se volvía accesible. Aquello que parecía una maravilla durante aquellos años, se fue volviendo una tarea muy compleja a medida que los softwares iban evolucionando y los años pasaban. Más dependencias, más frameworks y muchas configuraciones que se habían de trasladar para ejecutar un determinado servicio. Se fue popularizando la expresión «en mi máquina funciona» entre los desarrolladores y la gente de operaciones tenía muchos problemas de dependencias para desplegar estas nuevas versiones de las aplicaciones.
Para solucionar este problema, en 2013 nació Docker y la tecnología de los contenedores, una forma de virtualización más ligera (comparte Kernel con el host) que las máquinas virtuales porque no contiene un hardware virtual como sí lo hacen las VM.
Un contenedor encapsula todas las dependencias software y las configuraciones que necesita un programa generando un entorno cerrado para que el programa funcione adecuadamente. De esta forma, ganamos portabilidad, que es la principal ventaja de Docker. Esto simplificó muchísimo los despliegues y se empezó a popularizar la cultura de los microservicios, encapsular todo tipo de programas en estos contenedores para simplificar su gestión.
El problema es que cuando esto fue adoptado por la industria, la gestión manual de los contenedores, se volvió ineficiente. Por ejemplo, es imposible pensar que Google solo gestiona unos 10 contenedores, probablemente gestiona millones, y simplificar el despliegue era genial, pero con ello, nació una nueva necesidad. Un software que gestionara todos los contenedores y que minimizara tareas de optimización y revisión manuales como mejoras en la escalabilidad, revisara que no se produjeran fallos, o tuviera en cuenta la comunicación entre estos contenedores, aislados por defecto.
Todos estos aspectos fomentaron, en 2015, la creación, por parte de Google, de Kubernetes, un orquestrador de contenedores que solucionaba y simplificaba todos esos detalles. Este orquestrador funciona separando los componentes funcionales, por un lado, el Control Plane y por otra, los nodos Worker.
El Control Plane es el encargado del funcionamiento del clúster, tiene cuatro piezas fundamentales:
- Etcd: almacena la configuración (etcd).
- Controller Manager: Contiene todos los controladores, por ejemplo el de los nodos, encargado de monitorizar los workers y saber su estado, entre otros.
- Scheduler: Es el encargado de decidir qué contenedores van a cada nodo.
- Kube-apiserver: El Api que ofrece el Control Plane para gestionar todos estos detalles.
Los nodos Workers, son los encargados de ejecutar las cargas de trabajo, se dividen en tres partes. Podemos tener n workers y la funcionalidad del Control Plane es gestionarlos y dividirles las cargas de trabajo:
- Kubelet: Es un agente que se ejecuta en cada nodo y se encarga de que los contenedores estén desplegados en unas instancias llamadas «pods». Una de las funcionalidades principales es la supervisión de la salud y correcta ejecución de estos contenedores.
- Kube-proxy: Es el responsable del networking dentro de la red Kubernetes. Redirige peticiones, controla los permisos y aplica las políticas pertinentes para cumplir la comunicación deseada.
- Container runtime: Es el motor de ejecución de contenedores que utilizamos para la virtualización, típicamente containerd (Docker).
Las aplicaciones para ejecutarse en Kubernetes tienen que ser descritas mediante un archivo llamado manifiesto. Existen un tipo de recursos que se denominan Deployments y que son los encargados de definir nuestra aplicación.
Más allá de esta pequeña base, el networking por defecto es aislado, igual que en Docker, por defecto solo se pueden acceder a los contenidos internos, en Kubernetes igual. Aun así, hay mecanismos que indican al Proxy que tiene que permitir un flujo de comunicación determinado. Por eso existen unos componentes llamados Services, que tienen como función principal exponer una aplicación para que pueda ser accesible desde fuera del clúster (el caso del Load Balancer en la imagen superior).
Las principales ventajas de Kubernetes son la flexibilidad, la resiliencia y la alta disponibilidad que ofrece. Por ejemplo, cuando detecta que un contenedor ha tenido un fallo, lo vuelve a desplegar automáticamente. Cuando ve que un nodo Worker está muy cargado a nivel de recursos intenta (siempre que sea posible) balancear la carga entre los otros nodos del clúster, cosa que puede hacer gracias a la portabilidad de los contenedores, puesto que es muy sencillo mover un contenedor entre dos nodos.
Pero una de las funcionalidades más importantes de Kubernetes, teniendo en cuenta el auge del Cloud Computing, es la alta escalabilidad que ofrece. Tenemos componentes dentro de Kubernetes que son capaces de monitorizar la carga que está teniendo un contenedor y al superar unos determinados límites de recursos marcados por el administrador, escala la aplicación generando una copia del contenedor y dividiendo la carga entre los contenedores resultantes. De esta forma, aligera la carga del primer contenedor y reparte las peticiones entre los dos.
Esta casuística se ha vuelto muy interesante en el entorno Cloud, puesto que un sistema puede eventualmente, llegar a ser tan escalable como queramos. Si una aplicación tiene un pico de carga, Kubernetes de forma autónoma puede distribuir la carga entre el clúster para verificar el correcto funcionamiento de la aplicación. Pero dado el caso en que todos los nodos del clúster estuvieran experimentando una carga que impidiera el funcionamiento normal de la aplicación, hay otras herramientas que permiten aprovisionar nodos de forma automática al clúster con máquinas de proveedores Cloud para solucionar este pico sin downtimes.
En definitiva, los tiempos actuales han hecho de Kubernetes no una gran ventaja en la infraestructura, sino una necesidad debido a todas las ventajas que presenta, que solucionan problemáticas cotidianas y como hemos podido ver en este artículo, aligeran muchísimo la carga de trabajo de los administradores de sistemas y en entornos de grandes empresas donde esta complejidad se puede volver gigante si no se tiene un mecanismo de gestión adecuada como este.