455 - Desmitificando Docker o que hay bajo el capó

455 - Desmitificando Docker o que hay bajo el capó

¿En que se basa Docker o Podman?¿Que tecnologías utilizan estas dos herramientas para poner en marcha un contenedor? Ambas utilizan el Kernel.

1:25
-3:15

El próximo sábado día 21 de Enero, en el Linux Center de Slimbook voy dar un taller sobre Docker. Así que como puedes imaginar, me he estado preparando el taller. Desde luego, que todo el material que he estado preparando para el taller, los vas a poder encontrar en un repositorio en GitHub para que lo puedas aprovechar, si así lo consideras. La cuestión, es que con independencia de que se trate de un taller, si que quería hacer una introducción para tratar de bajar Docker o todo esto de la tecnología de los contenedores al mundo terrenal, y de ahí, el título de este episodio del podcast Desmitificando Docker o que hay bajo el capó.

Y es que parece que esto de la tecnología de los contenedores es algo de otro mundo, pero nada mas lejos de la realidad. De echo, gran parte de lo que hace Docker, lo puedes hacer perfectamente sin Docker.

Dismitificando Docker o que hay bajo el capó

Desmitificando Docker o que hay bajo el capó

¿Porque lo contenedores?

Ya que últimamente te vengo dando tanto la paliza con esto de los contenedores, está bien que te explique la razón que hay detrás de este amor incondicional a esta tecnología.

Y es que los contenedores vienen a resolver dos problemas relativos al software,

  • La compilación. Es muy posible que necesites una versión de una librería que tu no tienes instalada en tu equipo.
  • La distribución, despliegue e instalación. Por la misma razón, porque es muy posible que la máquina donde quieres hacer ese despliegue e instalación no tenga todas las librerías y dependencias necesarias.

Como ves se trata de al fin y al cabo de un problema de dependencias, tanto en la generación como en la distribución de software.

Pero ¿y si metemos dentro de un contenedor todas las dependencias que nuestra aplicación necesita? Y lo mismo sucede para la compilación. Utilizar un contenedor que tenga todas las herramientas y dependencias necesarias para compilar nuestra aplicación.

Sobre incluir todas las dependencias necesarias

Así por ejemplo, si quieres distribuir una aplicación que has implementado en Python, tu contenedor debe llevar en su interior,

  • el código de tu aplicación
  • todos los paquetes Python que utilice tu aplicación que puedes instalar con un requirements.txt
  • La versión de Python que necesites para ejecutar tu aplicación
  • libc y algunas otras librerías de sistema.

Todo esto es lo que básicamente se incluye en una imagen Docker, que no es mas que un tarball de un filesystem. Ni mas ni menos, ni menos ni mas.

Así que cuando construyes una imagen Docker, no estás hacinedo otra cosas que partir de tu sistema operativo, añadir tu código y dependencias, realizar las configuraciones que necesites y meterlo todo en un tarball.

Y por el contrario, cuando corres una imagen, lo que haces es justo el proceso contrario. Es decir, descargar el tarball, lo descomprimes en un directorio y ejecutas la aplicación como si ese directorio fuera el filesytesm.

Y precisamente aquí es donde reside la magia.

Un contenedor es un grupo de procesos Linux

Un contenedor no es mas que un grupo de procesos Linux, y para comprobarlo no tienes mas que abrir un par de consolas. En una de ellas entra y ejecuta top, mientras que en otra ejecuta,

ps -ef | grep top

Así cualquier proceso en un contenedor puede hacer lo mismo que un proceso normal, o casi. Y digo que casi, porque habitualmente, se le imponen una serie de restricciones.

  • Se limita la memoria
  • Se limitan las funcionalidades
  • Tiene restringidas algunas llamadas de sistema

Todas estas restricciones están impuestas por el Kernel.

¿Que características tiene un contenedor?

Llegados a este punto, está claro que no hay ninguna magia. Los contenedores aprovechan algunas características del kernel para hacer sus cosas.

  • Se trata de un proceso o grupo de procesos aislados del resto del sistema operativo utilizando lo que viene a continuación, los Namespaces.
  • Está aislado del sistema operativo utilizando Namespaces
  • Tiene una cantidad de recursos limitada utilizando Cgroups
  • Cuenta con un sistema de archivos independiente al sistema operativo en el que corre Chroot.

Vamos al detalle…

Sobre los processos

A estas alturas de tu vida Linuxera no te voy a explicar que es un proceso, pero, para aclararnos. Un proceso no es mas que una instancia de una aplicación, y que como bien sabes viene identificado por un PID. Esto, lo has podido ver cuando has ejecutado ese ps -ef | grep top, para comprobar que la ejecución de top en el contenedor se veía también desde fuera.

¿Namespaces?

Los Namespaces son una capa de abstracción de Linux, que permiten encapsular los recursos del sistema, de forma que los procesos en un Namespace puede tener una visión de los recursos del sistema distinto de los procesos de otro Namespace.

Existen distintos Namespaces,

  • cgroup directorio raíz de cgroup
  • ipc colas de mensajes
  • network dispositivos de red
  • mount puntos de montaje
  • pid los id de procesos
  • user los id de usuarios
  • uts los nombres de host y nombres de dominio

Los namespaces permiten que los procesos tengan sus propios puntos de montajes, pid, redes, etc.

Dentro de un contenedor las cosas se ven distintas. Así, cuando antes has hecho un top dentro del contenedor has visto solo cuatro procesos corriendo, por decirte algo. Mientras que fuera del contenedor ves decenas de procesos.

Además, si te has fijado el PID del proceso era distinto dentro del contenedor a fuera del contenedor. Fuera del contenedor, probablemente tenga un PID superior a 10000, mientras que dentro a lo mejor no llegaba ni a 100.

Por regla general un proceso utiliza el mismo namespace que su padre, sin embargo, tu puedes hacer que un proceso utilice un nuevo o nuevos namespace o que utilice alguno ya existente.

chroot y pivot_root

Como te he comentado anteriormente, una de las magias de esto de los contenedores es hacer que un directorio se convierta en el filesystem para un proceso. Esto se puede hacer con chroot. Esto es tan sencillo como ejecutar,

chroot $PWD aplicacion-que-quieras

Sin embargo, los contenedores en lugar de utilizar chroot utilizan pivot_root

cgroups

Un cgroup es un conjunto de procesos. Todos los procesos dentro de un contenedor están en el mismo cgroup. Es posible limitar tanto el uso de memoria y de CPU de un determinado cgroup.

Así, si un determinado proceso quiere consumir mas memoria o mas CPU, sabes que no lo podrá hacer por que está limitado. Y por supuesto, los cgroup registran el uso de cpu y memoria.

Conclusión

Como ves no hay ningún tipo de magia. Docker al igual que Podman, al igual que puedes hacer tu, simplemente utiliza algunas características del Kernel para funcionar.

  • Los namespace para definir los recursos y lo que pueden ver los procesos
  • cgroup para establecer y limitar los recursos que se pueden utilizar
  • pivot_root para establecer que el directorio en el que se encuentran los procesos como filesystem que verá cada proceso.

Más información,

Espero que te haya gustado este nuevo episodio del podcast. Si puedes, te agradecería una valoración en iVoox y/o en Apple Podcast.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *