Inicio / Software y Cloud / Contenedores: el embalaje que ha cambiado cómo viajan las aplicaciones

Contenedores: el embalaje que ha cambiado cómo viajan las aplicaciones

Contenedores: el embalaje que ha cambiado cómo viajan las aplicaciones

A finales del siglo XX un problema común en los centros de datos era el «en mi máquina funciona». Una aplicación que corría perfecta en el portátil del desarrollador se rompía en el servidor: faltaba una librería, la versión de Java era otra, el puerto ya estaba ocupado. Durante décadas la solución fue la máquina virtual: un ordenador entero emulado dentro de otro. Pero las máquinas virtuales son pesadas — cada una arrastra un sistema operativo completo. A partir de 2013 llegó una alternativa más fina que hoy domina internet: los contenedores.

¿Qué es exactamente un contenedor?

Un contenedor es un proceso aislado que empaqueta el código de una aplicación junto con todas sus dependencias: librerías, binarios, archivos de configuración y variables de entorno. La clave está en el verbo «aislado»: el contenedor cree que tiene su propio sistema operativo, aunque en realidad comparte el kernel (el núcleo) del host con todos los demás contenedores.

Esa es la gran diferencia con la máquina virtual. La VM virtualiza el hardware y carga un sistema operativo invitado completo, con su propio kernel — cientos de megabytes, a veces gigabytes, que se inician en minutos. El contenedor solo virtualiza el espacio de usuario y reutiliza el kernel del anfitrión: pesa decenas de megabytes y arranca en milisegundos. En el mismo servidor físico puedes lanzar decenas de contenedores donde antes cabían tres o cuatro máquinas virtuales.

Cómo se construye el aislamiento

El truco no es magia de un software nuevo, sino una combinación inteligente de mecanismos que ya llevaban años en el kernel Linux. Tres son los protagonistas.

Los namespaces (espacios de nombres) aíslan lo que el proceso «ve»: el PID 1 de un contenedor no es el PID 1 del host, su red, su sistema de archivos, sus usuarios y su hostname son mundos separados. El proceso piensa que es el dueño de la máquina, cuando en realidad es un inquilino.

Los cgroups (grupos de control) limitan lo que el proceso puede gastar: cuota de CPU, memoria máxima, ancho de banda de entrada y salida. Si un contenedor se descontrola y consume toda la RAM, el kernel lo frena o lo mata sin tumbar a sus vecinos. Es la garantía de que un inquilino ruidoso no arruine la fiesta.

Y en último término, las capabilities (capacidades) y seccomp (secure computing) recortan los privilegios: al proceso se le quitan las llamadas al sistema peligrosas, de modo que aunque un atacante rompa la aplicación no obtenga automáticamente el control de la máquina. La seguridad aquí se basa en la defensa en profundidad: varias capas independientes.

La imagen: el plano de construcción

Un contenedor se crea a partir de una imagen, un archivo inmutable y versionado que describe la aplicación y su entorno. Las imágenes se construyen con un Dockerfile, un pequeño script que enumera los pasos: «parte de esta base, instala estas dependencias, copia este código, expón este puerto, ejecuta este comando».

La imagen no es un bloque único, sino una pila de capas (layers). Cada instrucción del Dockerfile genera una capa, y Docker guarda en caché las capas que no han cambiado. Si solo modificas el código fuente, el sistema reutiliza las capas de las dependencias y solo recompila lo nuevo. Por eso subir y bajar imágenes por un registro (un repositorio central de imágenes, como Docker Hub) es tan rápido: los servidores comparten capas comunes en lugar de enviar todo desde cero cada vez.

Cuando lanzas un contenedor, sobre la imagen inmutable se añade una capa de escritura efímera: todo lo que la aplicación escribe al ejecutarse se queda ahí y desaparece al apagar el contenedor. Eso es lo que hace a los contenedores tan desechables: puedes matarlos y recrearlos miles de veces sin que ensucien el sistema.

El estándar OCI y la explosión del ecosistema

Para que tantas herramientas pudieran hablar entre sí, en 2015 se creó el Open Container Initiative (OCI), que definió dos estándares: el formato de imagen y la spec de runtime. Docker, que había popularizado la idea, acabó cediendo su motor a containerd (mantenido por la Cloud Native Computing Foundation), y hoy ese es el runtime que ejecutan la mayoría de los contenedores de producción. Por eso «hacer un contenedor» no significa ya «usar Docker»: existe Podman, containerd, CRI-O y otros motores que cumplen los mismos estándares.

El problema siguiente fue la escala. En producción no lanzas uno o dos contenedores: lanzas cientos. ¿Quién decide en qué servidor va cada uno, quién reinicia el que se cae, quién equilibra la carga? Para eso nacieron los orquestadores, y el que ha ganado la batalla es Kubernetes.

Kubernetes, o k8s, agrupa varios servidores en un clúster y los trata como un único ordenador virtual. Declaras el estado deseado — «quiero tres réplicas de esta API» — y el plano de control (control plane) trabaja sin descanso para que la realidad coincida con lo que pediste: si una réplica muere, el controlador (controller) lanza otra al instante. La aplicación no se entera de qué servidor la aloja: esa capa de abstracción es precisamente lo que permite a empresas como Netflix o Google escalar a millones de peticiones por segundo.

El coste y la práctica

Los contenedores no son gratis. Compartir el kernel significa que todos los procesos corren sobre el mismo sistema operativo del host, así que no puedes mezclar en la misma máquina un contenedor de Linux con una aplicación que exija Windows. Y el aislamiento, aunque robusto, es más fino que el de una máquina virtual: un atacante que consiga escapar del contenedor y explotar una vulnerabilidad del kernel podría comprometer al anfitrión. Por eso en entornos de máxima exigencia se combinan ambos: contenedores dentro de máquinas virtuales.

En la práctica, sin embargo, el modelo ha arrasado. Hoy casi todo lo que usas a diario — el backend de tu app de banca, las APIs que alimentan tu buscador, los microservicios de tu plataforma de streaming — corre en contenedores orquestados. El viaje que antes terminaba en un «en mi máquina funciona» ahora termina con la misma imagen corriendo idéntica en el portátil, el servidor de pruebas y el centro de datos de producción. El contenedor no resolvió solo un problema técnico: eliminó de golpe toda una categoría de excusas.