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.
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.
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 cgroupipc
colas de mensajesnetwork
dispositivos de redmount
puntos de montajepid
losid
de procesosuser
losid
de usuariosuts
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 utilizarpivot_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.