Herramientas de usuario

Herramientas del sitio


informatica:sistemas_operativos:cursos:docker_a_fondo_introduccion_kubernetes:introduccion_kubernetes

¡Esta es una revisión vieja del documento!


Introducción a Kubernetes

Notas del curso Docker a fondo e Introducción a Kubernetes: aplicaciones basadas en contenedores

En este módulo vas a aprender los fundamentos de Kubernetes, también conocido como k8s. Estudiaremos:

  • Qué es Kubernetes
  • El modelo de aplicación de Kubernetes
  • Cómo ejecutar Kubernetes en local
  • Ejecutar un contenedor en Kubernetes

Para seguir esta sección del curso debes poder ejecutar un clúster de Kubernetes en tu máquina. Por suerte hay multitud de proyectos que te pueden ayudar a ello. Para este curso se ha elegido Minikube.

Minikube es un proyecto, de la propia gente de Kubernetes, destinado a facilitar la ejecución de un clúster de Kubernetes en tu máquina de desarrollo. Más adelante te comento cómo instalar y ejecutarlo y se trata de una forma muy sencilla de que puedas seguir todo el curso.

Pero, Minikube no es la única opción disponible, hay muchos proyectos orientados a facilitar la creación y ejecución de clústeres de Kubernetes locales. Aunque la mayoría de ejemplos funcionarán en cualquier sistema, nosotros hemos preparado todos los ejemplos para que funcionen en Minikube. Si usas algún otro sistema es posible que en algunos casos debas adaptar algo (durante el curso intento avisar en aquellos casos en que, a lo mejor, el ejemplo requiera adaptación si no usas Minikube).

Algunas de las otras opciones disponibles son:

¿Qué es un orquestador (de contenedores)?

Un orquestador es un sistema que se encarga de ejecutar nuestros contenedores y de ofrecer a estos un conjunto de funcionalidades avanzadas tales como:

  • Escalado: un orquestador puede autoescalar nuestros contenedores creándolos y destruyéndolos según determinadas reglas de carga del sistema. Es cierto que con Compose podíamos escalar también, pero el escalado de Compose es fijo.
  • Multimáquina: un orquestador puede ejecutar contenedores en más de una máquina a la vez, de forma coordinada. Incluso pueden “mover” contenedores de máquina si es necesario.
  • Actualización de aplicaciones: suelen ofrecer mecanismos para actualizar las imágenes y configuración de nuestros contenedores de forma coordinada, sin paradas de servicio.
  • Versiones “canary”: puedes tener simultáneamente más de una versión en producción, permitiéndote así probar la “siguiente versión” (sirviéndola solo a determinados usuarios).
  • Métricas: ofrecen sistemas de métricas a nivel de contenedor, grupo de contenedores, máquina y orquestador.
  • Gestión de errores: si un contenedor no responde a peticiones pueden terminarlo e iniciar otro nuevo en su lugar.

Puede parecer que los orquestadores solo ofrecen ventajas en escenarios multimáquina, pero incluso en escenarios con una sola máquina pueden existir ventajas por utilizar un orquestador frente a hacerlo mediante Compose.

Qué es Kubernetes

Kubernetes fue un proyecto creado por Google a partir de su experiencia previa en el uso de contenedores. Su origen es un proyecto llamado Borg, que era un sistema propio de Google para la ejecución de gran cantidad de servicios heterogéneos para distintas aplicaciones, ejecutados de forma distribuida en grandes clústeres de máquinas. Muchas de las ideas de Borg se incorporaron a Kubernetes, en tanto que gran parte de los desarrolladores de Kubernetes lo fueron de Borg.

Kubernetes fue anunciado por Google en 2014 y la versión 1.0 salió en 2015. En aquel momento Google se alió con la Linux Foundation para formar la Cloud Native Computing Foundation (CNCF) y Kubernetes pasó a estar dirigido y desarrollado por esta última. Actualmente es de código abierto y se ha convertido en el líder del mercado de orquestadores de contenedores.

Componentes de Kubernetes

A pesar de que nos referimos a él simplemente como Kubernetes (o k8s), la realidad es que no se trata de un solo producto, sino de la combinación de varios. La siguiente lista muestra componentes open source independientes de Kubernetes, pero que son utilizados en este:

  • etcd: es una base de datos clave-valor distribuida que se utiliza para mantener el estado de todo el clúster.
  • supervisord: se trata de un monitorizador de procesos. En Kubernetes se usa para garantizar que tanto el daemon de Docker como el propio “kubelet”, el nodo de tipo agente principal de Kubernetes (luego lo veremos), se están ejecutando.
  • fluentd: es un sistema de logging unificado, que se usa en Kubernetes para centralizar todos los logs del clúster.

Además, existen varios componentes adicionales (kubelet, kube proxy, kube-controller manager y más) que forman parte de Kubernetes, pero que son más o menos independientes entre sí.

En este post de mi blog se detallan un poco más los componentes que conforman Kubernetes.

Nodos en Kubernetes

Todo clúster de k8s tiene dos tipos de nodos:

  • Nodos master: no suelen ejecutar contenedores, sino que se encargan de todas las tareas de sincronización, coordinación y toma de decisiones que afectan al conjunto del clúster.
  • Nodos minion (o worker): son los que se encargan de ejecutar los distintos contenedores.

El número mínimo de máquinas necesarias para montar Kubernetes es de uno (un clúster con un solo nodo). Kubernetes soporta clústeres de hasta 5000 nodos. Entre estos dos valores (1 y 5000) la cantidad de nodos será la que necesites.

El número mínimo de máquinas necesarias para montar un Kubernetes productivo de alta disponibilidad es de 5, tres de las cuales son nodos master y las dos restantes son nodos minion.

La creación de un nodo es algo externo a Kubernetes, generalmente lo crea el proveedor de cloud; o bien es una máquina física o virtual que tenemos, configuramos y agregamos al clúster. Lo que sí admite Kubernetes es agregar (o eliminar) máquinas a un clúster estando este en marcha.

Ver cómo desplegar un Kubernetes bare metal (es decir en máquinas, ya sean físicas o virtuales) está fuera del alcance de este curso. Si estás interesado, hay dos buenos recursos que puedes consultar: La documentación oficial y “Kubernetes The Hard Way”.

Una nota sobre el "no soporte a Docker" en Kubernetes 1.20

Hace cierto tiempo hubo una noticia que levantó bastante polvareda. Era algo similar a “Kubernetes dejará de soportar Docker a partir de la versión 1.20”. Aquí tienes la información oficial pero te pongo aquí el párrafo que importa:

Docker support in the kubelet is now deprecated and will be removed in a future release. The kubelet uses a module called “dockershim” which implements CRI support for Docker and it has seen maintenance issues in the Kubernetes community. We encourage you to evaluate moving to a container runtime that is a full-fledged implementation of CRI (v1alpha1 or v1 compliant) as they become available.

Esa noticia, que inicialmente se mencionó en un changelog rodeada de otros cambios que incorpora 1.20, enseguida fue amplificada por varios tweets y posts en blogs (algunos de ellos de colaboradores importantes de Kubernetes) que hicieron correr ríos de tinta, y se creó una alarma: ¿eso significa que los contenedores creados con Docker van a dejar de funcionar?

Mi respuesta a eso es muy sencilla: si te preocupas de que Kubernetes deje de soportar Docker como motor de contenedores entonces es que probablemente no te afecta. Porque para entender lo que implica realmente que Kubernetes deje de soportar Docker hay que comprender un poco la relación entre motores de contenedores y Kubernetes, y si la comprendes verás que los escenarios en que te puede afectar son pocos y relativamente avanzados (de forma que si los usas probablemente ya estarás manejando alternativas). Pero, resumiendo: que Kubernetes deje de soportar Docker no tiene (apenas) ninguna afectación.

En mi opinión, el pánico que generó esa noticia fue debido a una mala comunicación por parte del equipo de Kubernetes. Al final intentaron calmar las aguas con un post donde contaban las implicaciones pero, como pasa siempre en estos casos, la explicaciones suelen pasar más inadvertidas. Voy a intentar contarte en qué afecta que Kubernetes deje de soportar Docker sin entrar en demasiados tecnicismos (que algunos caen fuera del ámbito de este curso).

Cuando Kubernetes apareció, lo hizo con soporte para Docker, eso significa que hay código en Kubernetes para interactuar con el daemon de Docker para poner en marcha contenedores, pararlos, hacer pull de las imágenes, etc…

Poco tiempo después apareció un nuevo motor de contenedores, llamado rkt (lanzado por la gente de CoreOS (ahora Red Hat)) que parecía coger bastante tracción así que la gente de Kubernetes añadió soporte también a rkt en Kubernetes. Como nota a pie de página mencionar que rkt actualmente está deprecado y su uso ya no está recomendado.

Así que ahora la gente de Kubernetes tiene que soportar dos motores de contenedores, que son bastante distintos entre sí, pero con el tiempo sucedieron tres cosas más:

  • Docker dejó de ser completamente monolítico para modularizarse
  • La iniciativa OCI (Open Container Iniciative) empezó a tener calado
  • Surgieron nuevos motores de ejecución de contenedores, aparte de Docker, para ejecutar imágenes OCI

Entonces, la gente de Kubernetes se lanzó a una refactorización con el objetivo de que Kubernetes dejara de requerir el daemon de Docker o rkt y que pudiese utilizar cualquier motor de ejecución de contenedores. Eso haría que, tener que instalar Docker o rkt en los nodos dejase de ser necesario y daría libertad al administrador de cada clúster a usar cualquier motor de contenedores. Para ello, crearon una interfaz (llamada CRI) mediante la cual Kubernetes se podía integrar con cualquier motor de ejecución de contenedores. Además simplificaba el código de Kubernetes ya que traspasaba la responsabilidad de interactuar con el motor de contenedores a cada módulo CRI. Así, el código de Kubernetes dependía solo de la interfaz CRI y cada administrador del clúster podía instalar su propio motor de contenedores siempre y cuando hubiese una implementación de CRI para dicho motor. Todo esto sucedió hace ya mucho tiempo, allá por finales del 2016.

Poco después lanzaron dockershim: una implementación de CRI para usar Docker. El dockershim era pues la idea que había en Kubernetes para seguir soportando Docker, pero haciéndolo a través de CRI y no de forma “directa” como hasta entonces, simplificando el código del core de Kubernetes.

Así fueron evolucionando las cosas, pero con el tiempo el mantenimiento del dockershim se fue volviendo cada vez más pesado. Empezó a verse que el dockershim era superfluo, ya que (como ya sabes) Docker usa containerd para ejecutar contenedores, y containerd empezó a soportar CRI. Es decir, Kubernetes podía usar containerd directamente. Por lo tanto, en este escenario… ¿qué sentido tiene que Kubernetes use Docker, quien a su vez usa containerd, si podía usar containerd directamente?

Recuerda que containerd es un proyecto de Docker y ¡que es el motor de ejecución que usa Docker realmente por debajo!

Pero, si eso por sí solo no fuese suficiente, otra iniciativa había ganado ya madurez: CRI-O. CRI-O es un motor de ejecución de contenedores OCI y compatible con CRI.

Así pues, el escenario es el siguiente:

  • Docker genera (y ejecuta) imágenes OCI
  • Docker usa containerd para ejecutar contenedores
  • Kubernetes interacciona con el motor de contenedores a través de CRI
  • El dockershim es una implementación CRI para Docker, pero es compleja de mantener
  • Existe una implementación CRI para containerd
  • El proyecto CRI-O es un motor de ejecución de contenedores OCI que soporta CRI

Por lo tanto, es bastante evidente que Kubernetes no necesita mantener el dockershim para nada: gracias al CRI de containerd o a CRI-O puede ejecutar cualquier contenedor OCI. Y recuerda que Docker crea y ejecuta contenedores OCI.

Es por ello que se tomó la decisión, en Kubernetes 1.20, de marcar el dockershim como obsoleto (y dejar de soportarlo totalmente en 1.23). Pero, ¿qué implicaciones reales tiene?

  • ¿Podrás seguir ejecutando tus imágenes, generadas con docker build en Kubernetes? Por supuesto, ya que Docker construye imágenes OCI que son las que ejecuta Kubernetes.
  • ¿Puedes seguir usando Docker en desarrollo? Por supuesto, sin ningún problema. Docker “no desaparece” ni se va a ningún lado.
  • ¿Los nodos de Kubernetes deberán tener Docker instalado? No, en su lugar se podrá instalar containerd o bien CRI-O (o cualquier otro motor compatible con OCI y que tenga soporte CRI).

El último punto es el único que puede afectarte y se refiere a los escenarios avanzados que comentaba al principio. Básicamente, si ejecutas contenedores que requieren que Docker esté instalado en los nodos, porque hacen algo concreto con el daemon de Docker, entonces esto te afecta. Un caso típico es ejecutar un contenedor en Kubernetes que requiera a su vez construir otro contenedor. Lo más sencillo para hacer esto era enlazar este contenedor con el daemon de Docker del nodo de Kubernetes y ejecutar un docker build. Como puedes ver, ese es un escenario avanzado que va más allá de “ejecutar mis contenedores en Kubernetes”. Por eso comentaba al principio que si “te preguntas si eso te afecta, lo más probable es que no”, porque solo te afecta en esos casos avanzados, y en este momento probablemente ya tengas claro cómo Kubernetes ejecuta los contenedores y además ya conozcas alternativas a usar como pueden ser buildah o kaniko.

Así pues: tranquilidad. Puedes seguir usando Docker para crear y probar tus imágenes, y Kubernetes las podrá usar sin problemas :-)

Probar Kubernetes en local con Minikube

informatica/sistemas_operativos/cursos/docker_a_fondo_introduccion_kubernetes/introduccion_kubernetes.1708685227.txt.gz · Última modificación: por tempwin