¿En qué se diferencia Docker de una máquina virtual?
Sigo releyendo la documentación de Docker para intentar comprender la diferencia entre Docker y una VM completa. ¿Cómo logra proporcionar un sistema de archivos completo, un entorno de red aislado, etc. sin ser tan pesado?
¿Por qué es más fácil implementar software en una imagen de Docker (si ese es el término correcto) que simplemente implementarlo en un entorno de producción consistente?
Docker usó originalmente LinuX Containers (LXC), pero luego cambió a runC (anteriormente conocido como libcontainer ), que se ejecuta en el mismo sistema operativo que su host. Esto le permite compartir muchos de los recursos del sistema operativo host. Además, utiliza un sistema de archivos en capas ( AuFS ) y gestiona las redes.
AuFS es un sistema de archivos en capas, por lo que puede tener una parte de solo lectura y una parte de escritura fusionadas. Se podrían tener las partes comunes del sistema operativo como de solo lectura (y compartidas entre todos los contenedores) y luego darle a cada contenedor su propio soporte para escritura.
Entonces, digamos que tienes una imagen de contenedor de 1 GB; Si quisiera utilizar una máquina virtual completa, necesitaría tener 1 GB x la cantidad de máquinas virtuales que desee. Con Docker y AuFS puede compartir la mayor parte de 1 GB entre todos los contenedores y, si tiene 1000 contenedores, es posible que solo tenga un poco más de 1 GB de espacio para el sistema operativo de los contenedores (suponiendo que todos estén ejecutando la misma imagen del sistema operativo). .
Un sistema completamente virtualizado recibe su propio conjunto de recursos asignados y comparte un mínimo. Obtienes más aislamiento, pero es mucho más pesado (requiere más recursos). Con Docker obtienes menos aislamiento, pero los contenedores son livianos (requieren menos recursos). Por lo tanto, podría ejecutar fácilmente miles de contenedores en un host y ni siquiera parpadeará. Intenta hacer eso con Xen y, a menos que tengas un host realmente grande, no creo que sea posible.
Un sistema completamente virtualizado normalmente tarda unos minutos en iniciarse, mientras que los contenedores Docker/LXC/runC tardan unos segundos y, a menudo, incluso menos de un segundo.
Existen ventajas y desventajas para cada tipo de sistema virtualizado. Si desea un aislamiento total con recursos garantizados, una máquina virtual completa es el camino a seguir. Si solo desea aislar procesos entre sí y desea ejecutar una gran cantidad de ellos en un host de tamaño razonable, entonces Docker/LXC/runC parece ser el camino a seguir.
Para obtener más información, consulte este conjunto de publicaciones de blog que explican bien cómo funciona LXC.
¿Por qué es más fácil implementar software en una imagen acoplable (si ese es el término correcto) que simplemente implementarlo en un entorno de producción consistente?
Implementar un entorno de producción consistente es más fácil de decir que de hacer. Incluso si usa herramientas como Chef y Puppet , siempre hay actualizaciones del sistema operativo y otras cosas que cambian entre hosts y entornos.
Docker le brinda la posibilidad de tomar una instantánea del sistema operativo en una imagen compartida y facilita su implementación en otros hosts Docker. Localmente, dev, qa, prod, etc.: toda la misma imagen. Seguro que puedes hacer esto con otras herramientas, pero no tan fácil ni tan rápido.
Esto es genial para realizar pruebas; digamos que tiene miles de pruebas que necesitan conectarse a una base de datos y cada prueba necesita una copia impecable de la base de datos y realizará cambios en los datos. El enfoque clásico para esto es restablecer la base de datos después de cada prueba, ya sea con código personalizado o con herramientas como Flyway ; esto puede llevar mucho tiempo y significa que las pruebas deben ejecutarse en serie. Sin embargo, con Docker puede crear una imagen de su base de datos y ejecutar una instancia por prueba y luego ejecutar todas las pruebas en paralelo, ya que sabe que todas se ejecutarán en la misma instantánea de la base de datos. Dado que las pruebas se ejecutan en paralelo y en contenedores Docker, podrían ejecutarse todas en la misma caja al mismo tiempo y deberían finalizar mucho más rápido. Intente hacerlo con una máquina virtual completa.
De los comentarios...
¡Interesante! Supongo que todavía estoy confundido por la noción de "hacer una instantánea del sistema operativo". ¿Cómo se hace eso sin, bueno, hacer una imagen del sistema operativo?
Bueno, veamos si puedo explicarlo. Comienza con una imagen base, luego realiza los cambios y confirma esos cambios usando la ventana acoplable, y crea una imagen. Esta imagen contiene sólo las diferencias con la base. Cuando desea ejecutar su imagen, también necesita la base, y coloca su imagen encima de la base usando un sistema de archivos en capas: como se mencionó anteriormente, Docker usa AuFS. AuFS fusiona las diferentes capas y obtienes lo que deseas; solo necesitas ejecutarlo. Puede seguir agregando más y más imágenes (capas) y continuará guardando solo las diferencias. Dado que Docker generalmente se basa en imágenes listas para usar de un registro , rara vez es necesario "hacer una instantánea" de todo el sistema operativo usted mismo.
Puede resultar útil comprender cómo funcionan la virtualización y los contenedores a bajo nivel. Eso aclarará muchas cosas.
Nota: Estoy simplificando un poco la descripción a continuación. Ver referencias para más información.
¿Cómo funciona la virtualización a bajo nivel?
En este caso, el administrador de VM toma el control del anillo de CPU 0 (o el "modo raíz" en las CPU más nuevas) e intercepta todas las llamadas privilegiadas realizadas por el sistema operativo invitado para crear la ilusión de que el sistema operativo invitado tiene su propio hardware. Dato curioso: antes de 1998 se pensaba que era imposible lograr esto en la arquitectura x86 porque no había forma de realizar este tipo de interceptación. La gente de VMware fue la primera que tuvo la idea de reescribir los bytes ejecutables en la memoria para llamadas privilegiadas del sistema operativo invitado para lograrlo.
El efecto neto es que la virtualización le permite ejecutar dos sistemas operativos completamente diferentes en el mismo hardware. Cada sistema operativo invitado pasa por todos los procesos de arranque, carga del kernel, etc. Puede tener una seguridad muy estricta. Por ejemplo, un sistema operativo invitado no puede obtener acceso completo al sistema operativo anfitrión ni a otros invitados y estropear las cosas.
¿Cómo funcionan los contenedores a bajo nivel?
Alrededor de 2006 , personas, incluidos algunos empleados de Google, implementaron una nueva característica a nivel de kernel llamada espacios de nombres (sin embargo, la idea existía mucho antes en FreeBSD ). Una función del sistema operativo es permitir compartir recursos globales como redes y discos entre procesos. ¿Qué pasaría si estos recursos globales estuvieran incluidos en espacios de nombres para que solo fueran visibles para aquellos procesos que se ejecutan en el mismo espacio de nombres? Digamos que puede obtener una parte del disco y colocarla en el espacio de nombres X y luego los procesos que se ejecutan en el espacio de nombres Y no pueden verlo ni acceder a él. De manera similar, los procesos en el espacio de nombres X no pueden acceder a nada en la memoria asignada al espacio de nombres Y. Por supuesto, los procesos en X no pueden ver ni hablar con los procesos en el espacio de nombres Y. Esto proporciona una especie de virtualización y aislamiento para los recursos globales. Así es como funciona Docker: cada contenedor se ejecuta en su propio espacio de nombres pero usa exactamente el mismo kernel que todos los demás contenedores. El aislamiento ocurre porque el kernel conoce el espacio de nombres asignado al proceso y durante las llamadas a la API se asegura de que el proceso solo pueda acceder a los recursos en su propio espacio de nombres.
Las limitaciones de los contenedores frente a las máquinas virtuales deberían ser obvias ahora: no se pueden ejecutar sistemas operativos completamente diferentes en contenedores como en las máquinas virtuales. Sin embargo, puedes ejecutar diferentes distribuciones de Linux porque comparten el mismo kernel. El nivel de aislamiento no es tan fuerte como en una VM. De hecho, había una manera de que un contenedor "invitado" se hiciera cargo del host en las primeras implementaciones. También puede ver que cuando carga un contenedor nuevo, una copia completamente nueva del sistema operativo no se inicia como lo hace en una máquina virtual. Todos los contenedores comparten el mismo núcleo . Por eso los contenedores son livianos. Además, a diferencia de una máquina virtual, no es necesario preasignar una cantidad importante de memoria a los contenedores porque no estamos ejecutando una nueva copia del sistema operativo. Esto permite ejecutar miles de contenedores en un sistema operativo mientras los protegemos, lo que podría no ser posible si estuviéramos ejecutando copias separadas del sistema operativo en sus propias máquinas virtuales.