- La vista del sistema de archivos en procesos contenerizados
- El papel del Mount Namespace
- Imágenes de contenedores y rootfs
- Kernel compartido y dependencias de aplicaciones en contenedores
- El concepto de capas en las imágenes de contenedores
- Diseño de capas incrementales en imágenes de contenedores
- Capas en contenedores
- Ventajas del diseño en capas en imágenes de contenedores
- El impacto de las imágenes de contenedores en los flujos de trabajo de desarrollo de software
La vista del sistema de archivos en procesos contenerizados
¿Cómo se ve el sistema de archivos para los procesos que se ejecutan dentro de un contenedor? Uno podría pensar inmediatamente que esto se relaciona con el Mount Namespace: los procesos dentro de un contenedor deberían ver un sistema de archivos completamente independiente. De esta manera, se pueden realizar operaciones dentro de los directorios del contenedor, como /tmp, sin ninguna influencia del host o de otros contenedores. ¿Es este el caso, sin embargo?
El papel del Mount Namespace
Mount Namespace funciona de manera ligeramente diferente a otros namespaces, ya que su efecto en la visión del proceso contenerizado sobre el sistema de archivos solo se hace efectivo con una operación de montaje. Sin embargo, como usuarios regulares, deseamos un escenario más amigable: cada vez que se crea un nuevo contenedor, queremos que el proceso del contenedor vea un sistema de archivos que sea un entorno aislado, no uno heredado del host. ¿Cómo se puede lograr esto? No es difícil imaginar que podríamos remontar todo el directorio raíz “/” antes de iniciar el proceso del contenedor. Gracias a Mount Namespace, este montaje sería invisible para el host, permitiendo que el proceso del contenedor opere libremente dentro de él. En el sistema operativo Linux, existe un comando llamado chroot que puede realizar esta tarea convenientemente en una shell. Como su nombre indica, te ayuda a “cambiar el sistema de archivos raíz”, redirigiendo el directorio raíz del proceso a una ubicación especificada.
Imágenes de contenedores y rootfs
De hecho, Mount Namespace fue inventado basándose en mejoras continuas a chroot y es el primer Namespace en Linux. Para que este directorio raíz parezca más “real” para los contenedores, normalmente montamos un sistema de archivos completo de un sistema operativo en esta raíz, como una ISO de Ubuntu 16.04. En consecuencia, después de que el contenedor se inicie, ejecutar “ls /” dentro del contenedor revelará todos los directorios y archivos de Ubuntu 16.04. Este sistema de archivos montado en el directorio raíz del contenedor, que proporciona un entorno de ejecución aislado para los procesos del contenedor, se conoce como “imagen de contenedor”. También tiene un término más técnico: rootfs (sistema de archivos raíz). El /bin/bash ejecutado después de ingresar al contenedor es el archivo ejecutable bajo el directorio /bin, completamente distinto del /bin/bash del host. Ahora debes entender que el principio central detrás de los proyectos Docker implica esencialmente configurar Linux Namespace para el proceso de usuario que se va a crear, establecer parámetros específicos de Cgroups y cambiar el directorio raíz (Change Root) del proceso. Así nace un contenedor completo.
Kernel compartido y dependencias de aplicaciones en contenedores
Sin embargo, Docker prefiere usar la llamada al sistema pivot_root para el paso final del cambio, recurriendo a chroot si el sistema no admite pivot_root. Aunque estas dos llamadas al sistema tienen funcionalidades similares, existen diferencias sutiles. Además, es esencial aclarar que rootfs solo incluye los archivos, configuraciones y directorios de un sistema operativo, pero no el kernel. En Linux, estas dos partes se almacenan por separado, y la imagen del kernel de una versión específica solo se carga durante el arranque. Por lo tanto, rootfs incluye solo la “cáscara” del sistema operativo, no su “alma”. Entonces, ¿dónde está el “alma” del sistema operativo para los contenedores? En realidad, todos los contenedores en la misma máquina comparten el kernel del sistema operativo host. Esto significa que si tu aplicación necesita configurar parámetros del kernel, cargar módulos adicionales del kernel o interactuar directamente con el kernel, debes tener en cuenta que estas operaciones y dependencias apuntan al kernel del sistema operativo host, que es una “variable global” para todos los contenedores en esa máquina. Esta es una de las principales desventajas de los contenedores en comparación con las máquinas virtuales: estas últimas no solo tienen hardware simulado como sandbox, sino que también ejecutan un sistema operativo invitado completo dentro de cada sandbox para que las aplicaciones lo usen. No obstante, debido a la existencia de rootfs, los contenedores cuentan con una característica importante que ha sido ampliamente publicitada: la consistencia.
El concepto de capas en las imágenes de contenedores
¿Qué es la “consistencia” de los contenedores? Debido a las diferencias entre los entornos de servidores en la nube y locales, el proceso de empaquetado de aplicaciones siempre ha sido uno de los pasos más “dolorosos” al usar PaaS. Sin embargo, con los contenedores, o más precisamente, con las imágenes de contenedores (es decir, rootfs), este problema se ha resuelto de manera elegante. Dado que rootfs empaqueta no solo la aplicación sino todo el sistema operativo, encapsula todas las dependencias necesarias para que la aplicación se ejecute. De hecho, para la mayoría de los desarrolladores, su comprensión de las dependencias de aplicaciones se ha limitado al nivel del lenguaje de programación, como Godeps.json de Golang. Sin embargo, un hecho largamente pasado por alto es que, para una aplicación, el sistema operativo en sí mismo es la “biblioteca de dependencias” más completa que necesita para ejecutarse. Con la capacidad de las imágenes de contenedores para “empaquetar el sistema operativo”, este entorno de dependencia fundamental finalmente se convierte en parte del sandbox de la aplicación. Esto otorga a los contenedores su tan cacareada consistencia: sin importar si es en una máquina local, en la nube o en cualquier otro lugar, los usuarios solo necesitan desempaquetar la imagen del contenedor para recrear el entorno de ejecución completo requerido para que la aplicación se ejecute.
Diseño de capas incrementales en imágenes de contenedores
Esta consistencia a nivel de sistema operativo cierra la brecha entre el desarrollo local y los entornos de ejecución remotos para las aplicaciones. Sin embargo, es posible que hayas notado otro problema complicado: ¿necesitamos recrear rootfs cada vez que desarrollamos una nueva aplicación o actualizamos una existente? Una solución intuitiva podría ser guardar un rootfs después de cada operación “significativa” durante su creación, permitiendo que los colegas usen el rootfs que necesitan. Sin embargo, esta solución no es escalable. La razón es que una vez que los colegas modifican este rootfs, no hay relación entre el rootfs antiguo y el nuevo, lo que lleva a una fragmentación extrema. Dado que estas modificaciones se basan en un rootfs antiguo, ¿podemos hacer estos cambios de forma incremental? El beneficio de este enfoque es que todos solo necesitan mantener el contenido incremental en relación con el rootfs base, en lugar de crear un “fork” con cada modificación. La respuesta es, por supuesto, sí. Esta es precisamente la razón por la que Docker no siguió el proceso estándar de creación de rootfs al implementar imágenes de Docker, sino que hizo una pequeña innovación: Docker introdujo el concepto de capas en su diseño de imágenes. Cada operación que los usuarios realizan para crear una imagen genera una capa, que es un rootfs incremental. Esta idea no surgió de la nada, sino que utilizó una capacidad llamada Union File System (UnionFS), cuya función principal es montar unión (union mount) múltiples directorios de diferentes ubicaciones en un solo directorio.
Capas en contenedores

Capas en contenedores
Parte 1: Capas de solo lectura. Estas son las cinco capas inferiores del rootfs de este contenedor, que corresponden a las cinco capas de la imagen ubuntu:latest. Están montadas como solo lectura (ro+wh, es decir, readonly+whiteout). Cada capa contiene incrementalmente parte del sistema operativo Ubuntu.
Parte 2: Capa de lectura y escritura. Esta es la capa superior del rootfs de este contenedor (6e3be5d2ecccae7cc), montada como rw, o lectura-escritura. Antes de escribir cualquier archivo, este directorio está vacío. Una vez que se realiza una operación de escritura dentro del contenedor, las modificaciones aparecen incrementalmente en esta capa. Pero, ¿has considerado qué sucede si deseas eliminar un archivo de la capa de solo lectura? Para lograr esta eliminación, AuFS crea un archivo whiteout en la capa de lectura y escritura para “oscurecer” el archivo en la capa de solo lectura. Por ejemplo, eliminar un archivo llamado foo de la capa de solo lectura realmente crea un archivo llamado .wh.foo en la capa de lectura y escritura. Así, cuando estas capas se montan en unión, el archivo foo es oscurecido por el archivo .wh.foo y “desaparece”. Esta funcionalidad es lo que significa el método de montaje “ro+wh”, es decir, solo lectura más whiteout.
Parte 3: Capa Init. Esta es una capa interna generada por el proyecto Docker, que termina en “-init”, situada entre las capas de solo lectura y de lectura y escritura. La capa Init se usa específicamente para almacenar información como /etc/hosts y /etc/resolv.conf. La necesidad de tal capa surge porque estos archivos originalmente pertenecen a la imagen de solo lectura de Ubuntu, pero a menudo requieren valores específicos, como el nombre de host, que se escriben al iniciar el contenedor. Por lo tanto, se necesitan modificaciones en la capa de lectura y escritura. Sin embargo, estas modificaciones generalmente solo se aplican al contenedor actual y no están destinadas a ser confirmadas con la capa de lectura y escritura al ejecutar docker commit. Por lo tanto, el enfoque de Docker es montar estos archivos modificados en una capa separada. Cuando los usuarios ejecutan docker commit, solo se confirma la capa de lectura y escritura, excluyendo este contenido.
Ventajas del diseño en capas en imágenes de contenedores
A través del diseño de “imagen en capas”, con las imágenes de Docker como núcleo, técnicos de diferentes empresas y equipos están estrechamente conectados. Además, dado que las operaciones en las imágenes de contenedores son incrementales, el contenido extraído o enviado cada vez es mucho menor que múltiples sistemas operativos completos; las capas compartidas significan que el espacio total requerido para todas estas imágenes de contenedores es menor que la suma de cada imagen por separado. Esta agilidad en la colaboración basada en imágenes de contenedores supera con creces la de los discos de imágenes de máquinas virtuales, que pueden tener varios GB de tamaño. Más importante aún, una vez que se publica una imagen, descargarla en cualquier lugar del mundo produce exactamente el mismo contenido, reproduciendo completamente el entorno original creado por el creador de la imagen.
El impacto de las imágenes de contenedores en los flujos de trabajo de desarrollo de software
La invención de las imágenes de contenedores no solo une cada paso del proceso “desarrollo - prueba - despliegue”, sino que también significa que las imágenes de contenedores se convertirán en el método principal de distribución de software en el futuro. Este método de distribución ofrece ventajas como ser ligero, altamente consistente y facilitar la colaboración, haciendo que el desarrollo y despliegue de software sean más eficientes y confiables. Con su ligereza, consistencia y eficiencia, la tecnología de contenedores se está convirtiendo cada vez más en una herramienta esencial en el desarrollo y operaciones de software. A medida que la tecnología continúa evolucionando e innovando, hay razones para creer que la tecnología de contenedores desempeñará un papel aún más importante en el futuro.
Novita AI, la plataforma integral para la creatividad ilimitada 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 molestias del mantenimiento de GPU mientras construyes tus propios productos. Pruébalo gratis.
