Virtualización y Contenedores

Conceptos Generales

Virtualización

En un enfoque tradicional sobre un servidor o en un computador físico, se instala y se ejecuta un sistema operativo sobre el hardware para ejecutar aplicaciones encima de este.

Screenshot_5.png

La virtualización es una tecnología que crea recursos lógicos y los asigna a recursos físicos. Este proceso se puede realizar utilizando una funcionalidad de hardware específica o a través de una capa de software llamada manejador, monitor o hipervisor.

Screenshot_6.png

El objetivo de la virtualización es desacoplar el hardware del software para dividir y compartir recursos entre varias cargas de trabajo; máquinas virtuales y/o contenedores que ejecutan sistemas operativos y aplicaciones sobre ellas.

Screenshot_7.png

El uso de máquinas virtuales tiene varias ventajas, entre ellas podemos mencionar:

  • Una organización puede correr múltiples servicios en máquinas virtuales independientes, sin incurrir en los costos asociados con múltiples máquinas físicas. Por ejemplo, una organización puede correr servidor web, servidor de correo, LMS (Learning Management System), etc., en una sola máquina física.

  • No todas las aplicaciones aprovechan la escalabilidad vertical de una máquina: agregar CPU, memoria u otros recursos a una máquina puede terminar en recursos que son subutilizados. La virtualización permite segregar estos recursos y que una aplicación reciba solo aquellos que puede utilizar eficientemente.

  • Además, las máquinas virtuales ofrecen una forma de “empaquetar” una plataforma o aplicación con todos las dependencias y componentes necesarios para facilitar su despliegue. Sin embargo, este esquema puede ser más pesado de lo necesario; una aplicación puede ser liviana y tener pocas dependencias y aun así requerirá una máquina virtual completa generando el desperdicio de recursos.

Contenedores

Un contenedor responde a la misma necesidad de empaquetar una aplicación, pero crea una estructura contenedora más liviana. Esta estructura solo contiene la aplicación, sus dependencias y posiblemente algunos servicios del sistema operativo, en vez de un sistema operativo completo. Se puede decir que los contenedores crean un nivel de virtualización adicional (comparados con las máquinas virtuales) y virtualizan el sistema operativo (en lugar de la máquina completa).

Screenshot_8.png

Es posible ejecutar un contenedor en cualquier ambiente que ejecute el mismo kernel, por lo tanto, es posible mover un contenedor entre máquinas con el mismo kernel sin cambiar o reiniciar nada.

Los contenedores comparten el mismo kernel del sistema operativo porque son solo procesos aislados. Simplemente agregaremos un sistema de archivos con plantilla y recursos (CPU, memoria, de disco, red, etc) a un proceso.

Los contenedores se ejecutan en un espacio aislado en el interior y solo utilizarán su entorno definido. Como resultado, los contenedores son livianos y se inician y se detienen tan rápido como sus procesos principales. Los contenedores son tan livianos como los procesos que ejecutan, ya que no tenemos nada más ejecutándose dentro de un contenedor. Todos los recursos que consume un contenedor están relacionados con el proceso.

La diferencia entre un contenedor y máquina virtual es la ubicación de la capa de virtualización y la forma en que se utilizan los recursos del sistema operativo. Un contenedor y una máquina virtual son diferentes tecnologías para aprovisionar recursos de cómputo (CPU, memoria, etc) que ya están presentes en una computadora física. Aunque el objetivo es el mismo, el enfoque es notablemente diferente y cada enfoque ofrece características y compensaciones únicas para las cargas de trabajo.

En la oferta de contenedores encontramos un mercado similar con algunas diferencias técnicas que vale la pena comprender:

  • Docker: Docker es la plataforma de contenedores más conocida y utilizada del mercado. Docker es una tecnología que le permite agregar y almacenar una aplicación y sus dependencias en un paquete llamado imagen. Esta imagen se puede usar para generar una instancia de su aplicación, el contenedor.

  • rkt: Distribuido por CoreOS, como una alternativa a Docker centrada en la seguridad.

  • LXC: Distribuida por Canonical Ltd., la empresa detrás de Ubuntu con el objetivo de ofrecer contenedores de sistema completo. LXD es un MMV de contenedores más centrado en el sistema operativo que en la aplicación.

  • VServidor Linux: Proporciona capacidades de contenerización a nivel de sistema operativo a través de un kernel de Linux modificado.

Microsoft también ha introducido la función de contenedores de Windows desde Windows Server 2016. Actualmente, existen dos tipos de contenedores de Windows

  • Contenedores de Windows: Similares a Docker, los contenedores de Windows usan espacios de nombres y límites de recursos para aislar los procesos entre sí. Estos contenedores comparten un kernel común, a diferencia de una máquina virtual que tiene su propio kernel.

  • Contenedores de Hyper-V: los contenedores de Hyper-V son máquinas virtuales totalmente aisladas altamente optimizadas que contienen una copia del kernel de Windows. A diferencia de los contenedores Docker que aíslan procesos y comparten el mismo kernel, los contenedores Hyper-V tienen cada uno su propio kernel.

Docker

Docker es una plataforma que le permite construir, enviar/mover y ejecutar cualquier aplicación, en cualquier lugar. Los contenedores han recorrido un largo camino en un tiempo increíblemente corto y ahora se considera una forma estándar de resolver uno de los aspectos más costosos del software, el despliegue.

Docker y en general las tecnologías de contenedores mueven las aplicaciones entre los entornos de desarrollo, prueba y producción con agilidad, pero también permiten adoptar la nube minimizando el esfuerzo de adopción.

Para entender Docker, realicemos un símil con un operario que trasladaba productos comerciales dentro y fuera de los barcos de carga cuando atracaban en los puertos. En el barco de carga hay cajas y artículos de diferentes tamaños y formas; los operarios experimentados fueron apreciados por su capacidad de acomodar bienes en los barcos a mano de manera rentable. Contratar personas para mover los productos no era barato.

Los sistemas modernos de carga transportan los productos comerciales dentro del barco en contenedores y fuera de los barcos no es importante el producto sino poder mover el contenedor. Para esto se requiere un solo operario de grúa que mueve los contenedores del barco al puerto, sin importarle su contenido y la estandarización facilita optimizar los tiempos de traslado.

Cuando hablamos de contenedores, debemos comprender los componentes que habilitan esta tecnología:

  • Runtime: El runtime es la aplicación y las características del sistema operativo que hacen posible la ejecución y el aislamiento del proceso. En el caso de Docker, este proporciona un runtime contenedores llamado Docker.

  • Imágenes: Las imágenes son plantillas para crear contenedores. Las imágenes contienen todo lo requerido por nuestro proceso para operar correctamente (binarios, bibliotecas, archivos de configuración, etc.).

Screenshot_9.png
  • Una característica importante de las imágenes es que son inmutables, es decir, no cambian entre ejecuciones. Con cada imagen se obtienen los mismos resultados. Las imágenes de Docker se crean a partir de una serie de capas, y todas estas capas empaquetadas contienen todo lo necesario para ejecutar un proceso. Todas las capas son de solo lectura y los cambios se almacenan en la siguiente capa superior durante la creación de la imagen y cada capa solo tiene un conjunto de diferencias con respecto a la capa anterior.

  • Las capas están empaquetadas para facilitar el transporte entre diferentes entornos e incluyen información sobre la arquitectura requerida para ejecutarse. Las imágenes incluyen información sobre cómo se debe ejecutar el proceso, dónde persiste la información, qué puertos expondrá el proceso para comunicarse, etc.

  • En el caso de Docker, las imágenes se pueden construir con métodos reproducibles usando Dockerfiles o almacenar cambios realizados en contenedores en ejecución para obtener una nueva imagen.

  • El contenedor: un contenedor es un proceso como lo mencionamos previamente. Los contenedores se crean utilizando imágenes como plantillas. De hecho, un contenedor agrega una nueva capa de lectura y escritura en la parte superior de las capas de imagen para almacenar las diferencias del sistema de archivos de estas capas.

  • Todas las capas de imágenes son capas de solo lectura, los cambios se almacenan en la capa de lectura y escritura del contenedor, pero estos cambios se perderán cuando se elimina un contenedor, pero la imagen permanecerá inmutable hasta que sea borrada.

  • Esta característica permite ejecutar muchos contenedores usando la misma imagen subyacente, y cada uno almacenará los cambios en su propia capa de lectura y escritura. Es importante resaltar que los contenedores no son efímeros para un host; cuando se ejecuta un contenedor en un host, permanecerá allí hasta que alguien lo elimine. Se puede iniciar un contenedor detenido en el mismo host si aún no se ha eliminado conservando lo que está dentro de este, pero no es un buen lugar para almacenar el estado del proceso porque solo es local para ese host.

Screenshot_10.png
  • Aislamiento de procesos: Un kernel proporciona espacios de nombres para el aislamiento de procesos. Cada contenedor se ejecuta con sus propios espacios de nombres de kernel para lo siguiente: Procesos, red, IPC, puntos de montaje, UTS.

  • Registro: El único requisito para aprovisionar un contenedor en un nuevo nodo es la imagen para crear ese contenedor y recursos de cómputo. La imagen se puede compartir entre nodos, para garantizar la distribución de imágenes se utilizan registros de imágenes, que son puntos de almacenamiento para este tipo de objetos, similares a un repositorio, similar a los repositorios de código como Github ofreciendo control de versiones de la imagen.

Cuando utilizar Docker

Cuando hablamos de una tecnología específica, como lo es Docker, siempre nos preguntamos: ¿Cuándo utilizar Docker? Surgen algunas preguntas prácticas cruciales: ¿por qué usaría Docker y para qué? La respuesta simple al "por qué" es por un mínimo esfuerzo. Analicemos el cuándo y el para qué.

Screenshot_11.png

Docker u otro de sus equivalentes se puede usar para reemplazar máquinas virtuales en muchas situaciones. Si solo importa la aplicación, no el sistema operativo, estos pueden reemplazar la VM y facilitan dejar de preocuparse por el sistema operativo.

Antes de los contenedores Docker, el despliegue de aplicación en diferentes entornos requería un esfuerzo considerable. Incluso si no estuviera ejecutando scripts para aprovisionar software en diferentes máquinas (y mucha gente todavía hace exactamente eso), se debe asumir el costo de gestionar las herramientas de administración de configuración.

Un contenedor Docker es un paquete de software que comprende todo lo necesario para ejecutar una aplicación de forma independiente. Puede haber múltiples contenedores Docker en una sola máquina y los contenedores son procesos independientes en el sistema operativo del host. En otras palabras, un contenedor Docker incluye un componente de software junto con todas sus dependencias (binarios, bibliotecas, archivos de configuración, scripts, etc.). El contenedor Docker tiene su propio espacio de proceso e interfaz de red.

Recordemos: Un proceso es un mecanismo de interacción con un sistema operativo. Un programa es un conjunto de instrucciones para ejecutar en el sistema; un proceso será ese código en ejecución. Los procesos utilizan recursos de máquina (CPU, memoria, etc.) y aunque se ejecutará en su propio entorno, puede compartir información con otro proceso que se ejecute en la misma máquina. Los contenedores, como se mencionó previamente son procesos aislados en el sistema, pero se pueden comunicar por red.

Los contenedores son ideales en entornos donde se requieran características como despliegue rápido, alta escalabilidad y tolerancia a fallos. Los contenedores son un habilitador para el desarrollo de aplicaciones con arquitecturas de nueva generación, como las arquitecturas de microservicios y las arquitecturas Cloud Native.

Docker es ideal para implementar microservicios (un habilitador para Cloud Native), ya que facilita la descomposición de un sistema complejo en una serie de piezas. Esto puede permitirle reestructurar su software para que sus partes sean más manejables e integrables sin afectar el conjunto.

Docker como un habilitador para continuous delivery. La entrega continua (CD) es un paradigma para la entrega de software basado en un pipeline que reconstruye el sistema en cada cambio y luego entrega a producción a través de un proceso automatizado (o parcialmente automatizado).

En pocas palabras, Docker nos permite ensamblar rápidamente aplicaciones empresariales y críticas para el negocio. Para hacer esto, podemos usar componentes de software diferentes y distribuidos; Docker también nos permite probar el código y luego implementarlo en producción lo más rápido posible.

En última instancia, la elección de contenedores frente a máquinas virtuales no es mutuamente excluyente. Los contenedores y las máquinas virtuales pueden coexistir fácilmente en el mismo ambiente, incluso en el mismo servidor, por lo que las dos tecnologías se consideran complementarias.

Referencias

  1. Virtualization - Modern Operating Systems, 4th edition, A. Tanenbaum, H. Bos, Pearson.

  2. Docker for Developers. Chris Tankersley. Leanpub Publishing.

  3. Learning Docker. Petheru Raj, Vinod Sing. Packt Publishing.

Did you find this article valuable?

Support Jesse Padilla by becoming a sponsor. Any amount is appreciated!