Contenedores y Máquinas Virtuales
Si llevas tiempo administrando infraestructura, el debate ya te resulta familiar: VMs o contenedores. Durante años la respuesta por defecto era levantar una VM. Hoy todo el mundo mete sus cargas de trabajo en Docker y da el tema por cerrado, sin entender bien por qué.
El problema es que ambas tecnologías resuelven el aislamiento de formas arquitectónicamente opuestas. Entender qué hace cada una a nivel de kernel no es trivia académica: es lo que te permite tomar la decisión correcta en lugar de seguir la moda de turno.
Máquinas Virtuales (VMs): Aislamiento basado en Hardware
Una VM emula un sistema informático físico completo. Para lograrlo necesita un Hypervisor (VMware ESXi, Hyper-V, KVM), que puede instalarse directamente sobre el hardware físico (bare metal) o encima de un sistema operativo anfitrión. Su trabajo es tomar los recursos físicos, CPU, RAM, discos, red, y repartirlos lógicamente entre las VMs.
¿Cómo funciona internamente? Cada VM corre su propio Sistema Operativo Invitado (Guest OS) completo, con sus binarios, librerías y la aplicación encima. Tres VMs en un servidor físico significa cuatro kernels arrancando en paralelo: el host más los tres invitados. Toda esa memoria está ocupada antes de que tu aplicación procese una sola petición. Es overhead que pagas aunque no hagas nada.
Ventajas:
- Aislamiento Fuerte: La emulación de hardware levanta una barrera a nivel de kernel que los contenedores no alcanzan. Un fallo o vulnerabilidad en el kernel de una VM no se propaga a las demás, y eso no es un detalle menor si manejas entornos multicliente o workloads regulados.
- Sistemas Operativos Heterogéneos: Puedes correr Windows Server, Debian y FreeBSD en el mismo hierro, al mismo tiempo, sin compromisos.
Desventajas:
- Consumo de Recursos: Cada SO invitado quema RAM y CPU solo por existir, antes de servir una sola petición. El overhead se acumula rápido, y en servidores con decenas de VMs se vuelve el principal cuello de botella.
- Tiempo de Arranque Lento: Levantar una VM no es ejecutar un proceso. Hay que arrancar el kernel completo, iniciar servicios, configurar la red, todo el ciclo. Decenas de segundos en el mejor caso, minutos si la imagen es pesada.
Contenedores: Aislamiento basado en el Sistema Operativo
Los contenedores no emulan hardware. Virtualizan el Sistema Operativo directamente, usando primitivas que ya viven en el kernel de Linux desde hace más de una década.
Las dos que sostienen todo son:
- Namespaces: Le mienten al proceso, haciéndole creer que es el único corriendo en el sistema. Le dan su propio árbol de PIDs, sus puntos de montaje, su stack de red. El proceso nunca ve lo que hay fuera.
- Cgroups (Control Groups): Limitan cuánta CPU, RAM y E/S de disco puede consumir un proceso. Sin cgroups, un contenedor mal configurado tumbaría el host entero. Los he visto hacerlo.
¿Cómo funciona internamente? Todos los contenedores del host comparten el mismo kernel de Linux. Solo uno. Lo que empaqueta el contenedor es la aplicación, las librerías que necesita y sus dependencias directas. El kernel ya está ahí, cedido por el host.
Ventajas:
- Eficiencia Extrema: Sin SO invitado, el overhead es casi inexistente. El contenedor consume la RAM de tu aplicación, no la de un sistema operativo que nadie pidió.
- Arranque Instantáneo: Levantar un contenedor tarda lo mismo que ejecutar un binario. Milisegundos, no minutos. Eso cambia cómo diseñas el escalado.
- Portabilidad Real: Si corre en tu laptop, corre igual en producción, porque el contenedor lleva sus dependencias consigo y no asume nada del entorno anfitrión.
Desventajas:
- Mismo Kernel: Todos los contenedores tienen que ser compatibles con el kernel del host. No puedes correr un contenedor nativo de Windows sobre Linux sin meter una VM de por medio, y eso complica algunos escenarios de desarrollo en Windows.
- Aislamiento Menor: Los Namespaces separan los procesos, pero el kernel es compartido. Una vulnerabilidad grave a nivel de kernel puede comprometer todos los contenedores del mismo host. No es teoría: ha pasado en producción, con CVEs reales y downtime real.
¿Cuál deberías elegir? Casos de Uso Prácticos
La pregunta está mal planteada. En producción casi nunca eliges una u otra, usas las dos. Lo habitual es provisionar VMs en la nube (instancias EC2, Compute Engine, lo que sea) y correr el motor de contenedores dentro de esas VMs. Una capa da el aislamiento duro de kernel, la otra da densidad y velocidad de despliegue. Yo llevo años operando exactamente esa combinación y no conozco una alternativa más práctica a escala.
Usa Máquinas Virtuales cuando:
- Necesitas aislar infraestructuras críticas donde la separación de kernel es no negociable: entornos multicliente hostiles, PCI-DSS, cargas de trabajo con requisitos de cumplimiento normativo estrictos.
- Tienes que correr sistemas operativos radicalmente distintos en el mismo hardware, Linux y Windows conviviendo sin que uno afecte al otro.
- Estás ejecutando aplicaciones monolíticas legacy que nunca fueron pensadas para entornos efímeros y que revisar costaría más que migrar el hierro.
Usa Contenedores cuando:
- Estás construyendo arquitecturas de microservicios donde cada componente tiene que escalar de forma independiente, sin arrastrar consigo el peso de un SO completo.
- Tus ciclos de CI/CD no pueden permitirse esperar a que arranque una VM. Los contenedores son pequeños, se construyen en segundos y se despliegan más rápido aún.
- Quieres exprimir la densidad del servidor, corriendo cientos de procesos aislados sin el coste en RAM que traerían cientos de VMs.
La elección real no es VMs contra contenedores. Es entender qué capa de aislamiento necesita cada carga de trabajo, y no asumir que la última herramienta de moda resuelve todos los problemas. Docker no desplazó a las VMs. Las complementó.