Principios de la virtualización de contenedores

Principios de la virtualización de contenedores

Entendiendo la tecnología de contenedores

Los contenedores son un tipo de tecnología de sandbox. Como sugiere el nombre, un sandbox es una tecnología que puede “empaquetar” aplicaciones como un contenedor, asegurando que las aplicaciones no interfieran entre sí debido a los límites establecidos. Además, las aplicaciones contenidas dentro de estos “contenedores” pueden migrarse y ejecutarse en diferentes entornos de sistema. Antes de profundizar en los principios detrás de la tecnología de contenedores, es esencial comprender el concepto de procesos. La representación estática de un proceso es un programa, que normalmente descansa silenciosamente en un disco. Una vez que se ejecuta, se transforma en la suma de datos y estados dentro de la computadora: su representación dinámica. La funcionalidad central de la tecnología de contenedores implica crear un “límite” para los procesos al restringir y modificar sus comportamientos dinámicos.

Tecnología de contenedores Docker

Para la mayoría de los contenedores Linux, incluido Docker, la tecnología Cgroups se utiliza principalmente para imponer restricciones, mientras que la tecnología Namespace es el método principal para modificar la vista del proceso. Imagina que tienes un proyecto Docker ejecutándose en un sistema operativo Linux, por ejemplo, Ubuntu 22.04. Vamos a crear un contenedor para experimentar:

$ docker run -it busybox /bin/sh

Este comando Docker inicia un contenedor basado en la imagen busybox y ejecuta una sesión interactiva de shell dentro de él.

  • docker run: Crea e inicia una nueva instancia de contenedor.
  • -i: Mantiene STDIN abierto incluso sin un terminal adjunto, permitiendo la interacción con el contenedor.
  • -t: Asigna un pseudo-terminal o terminal, creando un entorno de shell interactivo.
  • /bin/sh: Especifica el comando a ejecutar al iniciar el contenedor, que en este caso lanza una sesión de shell dentro del contenedor.

Procesos dentro del contenedor

Por lo tanto, la máquina Ubuntu se convierte en un host, y un contenedor ejecutando /bin/sh opera dentro de él. Este ejemplo y su principio subyacente deberían ser familiares para los usuarios experimentados de Docker. Si ejecutas el comando ps dentro del contenedor, notarás algo interesante:

/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
10 root 0:00 ps

Aquí, el /bin/sh inicial ejecutado dentro de Docker es el proceso número 1 (PID=1) dentro del contenedor, con solo dos procesos ejecutándose. Esto implica que el /bin/sh y el comando ps que acabamos de ejecutar han sido aislados dentro de un entorno distinto al del host.

El mecanismo Namespace

¿Cómo se logra esto? Normalmente, cuando un programa /bin/sh se ejecuta en el host, el sistema operativo le asigna un ID de proceso, como PID=100, que lo identifica de manera única. Cuando se ejecuta este programa dentro de un contenedor Docker, Docker aplica una “ilusión” para que el proceso, que en realidad es PID=100, crea que es el primer proceso (PID=1). Este mecanismo manipula el espacio de procesos de las aplicaciones aisladas, permitiéndoles ver IDs de proceso recalculados.

La tecnología Namespace de Linux

El uso de Namespaces es bastante interesante: es simplemente un parámetro opcional para crear nuevos procesos en Linux. La llamada al sistema para crear procesos en Linux es clone(), de la siguiente manera:

int pid = clone(main_function, stack_size, SIGCHLD, NULL);

Esta llamada crea un nuevo proceso y devuelve su ID de proceso, pid. Al usar la llamada al sistema clone() para crear un nuevo proceso, se puede especificar el argumento CLONE_NEWPID:

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

El proceso recién creado “verá” entonces un espacio de proceso nuevo donde su PID es 1. Esta “ilusión” no cambia el PID real en el espacio de procesos del host, que sigue siendo el valor real, como 100.

Múltiples Namespaces en acción

La ejecución repetida de la llamada clone() anterior crearía múltiples PID Namespaces. Los procesos de aplicación de cada Namespace creen que son el primer proceso dentro de sus respectivos contenedores, sin conocer el espacio de procesos real del host ni los detalles de otros PID Namespaces. Además del PID Namespace, Linux ofrece Mount, UTS, IPC, Network y User Namespaces para “ocultar” varios contextos de procesos.

Mount Namespace

  • Mount Namespace: Permite que los procesos aislados vean solo los puntos de montaje relevantes para el Namespace actual, lo que significa que los procesos dentro del contenedor desconocen otros puntos de montaje en el host.

Network Namespace

  • Network Namespace: Proporciona a los procesos aislados una vista de los dispositivos y configuraciones de red específicos del Namespace actual. Cada Network Namespace tiene sus propios dispositivos de red, direcciones IP, tablas de enrutamiento y números de puerto, separados del host y de otros Namespaces.

Otros Namespaces

  • UTS Namespace: Aísla la información del nombre del nodo (hostname) y del nombre de host de red.
  • IPC Namespace: Segrega los recursos para la comunicación entre procesos, como colas de mensajes y semáforos.
  • User Namespace: Aísla los IDs de usuario y grupo, permitiendo mapear IDs de usuario dentro del contenedor a IDs diferentes en el host para mayor seguridad.

El principio de implementación de los contenedores Docker

Este es el principio fundamental de implementación de los contenedores Linux. Por lo tanto, el concepto aparentemente complejo de los contenedores Docker implica esencialmente especificar un conjunto de parámetros Namespace al crear un proceso de contenedor. En consecuencia, el contenedor solo puede “ver” los recursos, archivos, dispositivos, estados o configuraciones limitados por el Namespace actual, permaneciendo completamente ajeno al host y a los programas no relacionados.

Comparando contenedores con máquinas virtuales

Por lo tanto, los contenedores son un tipo especial de proceso. Al considerar la idea de asignar un espacio independiente para los procesos, vienen a la mente las máquinas virtuales. Estas simulan hardware mediante software Hypervisor, ejecutando un sistema operativo invitado completo para lograr el aislamiento de aplicaciones. En contraste, los contenedores Docker logran el aislamiento mediante la tecnología Namespace y Cgroups mientras comparten el kernel del sistema operativo del host.

Virtualización ligera de Docker

Docker a menudo se denomina tecnología de virtualización “ligera” porque utiliza directamente los recursos del host sin necesidad de simulación de hardware ni ejecución de un sistema operativo adicional. Esto resulta en ventajas significativas sobre las máquinas virtuales tradicionales en términos de velocidad de inicio, utilización de recursos y rendimiento.

Conclusión

La tecnología de contenedores Docker proporciona un entorno aislado pero ligero para los procesos de aplicación mediante la tecnología Namespace y Cgroups. Esta tecnología permite que los contenedores se inicien rápidamente, se ejecuten de manera eficiente y mantengan el aislamiento del host y de otros contenedores, convirtiéndola en una tecnología indispensable en la computación en la nube moderna y las arquitecturas de microservicios.

Novita AI, la plataforma integral para la creatividad sin límites que te brinda acceso a más de 100 APIs. Desde generación de imágenes y procesamiento de lenguaje hasta mejora de audio y manipulación de video, con pago por uso económico, te libera de las tareas de mantenimiento de GPU mientras construyes tus propios productos. Pruébalo gratis.