En muchos artículos hoy se habla de microservicios, contenedores (containers) y máquinas virtuales. Presentan el tema como parte de un tutorial de los que van a usarlo. Pero en pocos artículos se presenta el tema para los que simplemente quieren saber qué es y qué ventajas trae.
En este simple y (no tan) breve artículo presentaré el tema desde ese punto de vista.
Aplicaciones y Sistemas Operativos
Quiero partir de una base común universal. Entiendo que sabes lo que es una aplicación. Aún si no lo sabes, seguro que si has usado una computadora, has usado una aplicación.
Ejemplos de aplicaciones son Excel, MS Word para editar textos, o hasta el navegador que está usando para leer este artículo, que podría ser Chrome o Firefox.
Si tienes una Mac estarás más familiarizado con aplicaciones como Garage Band para hacer arreglos musicales o el iMovie para editar videos.
Te habrás dado cuenta que muchas de esas aplicaciones vienen con la computadora cuando la comprás y muchas otras las instalas, ya sea comprando una licencia o bajándolas de la web.
Pero no puedes instalar el Excel para Windows directamente en una Mac o el Garage Band de la Mac en un Windows. Windows es un sistema operativo, y Mac tiene otro sistema operativo que es el Mac OS es el sistema operativo de las Macs. Si bien los celulares también tienen sus sistemas operativos como Android (para teléfonos Androd) o IOS para iPhone. Cuando hablamos de maquinas virtuales y contenedores como Docker no los relaciono con sistemas operativos de smart phones.
Aplicaciones para cada sistema operativo
En los ejemplos mencionados, las aplicaciones son practicamente autosuficientes, no necesitan otra aplicación para hacerlas andar. Simplemente necesitan el sistema operativo (ej: Windows o Mac OS o Linux o Unix)
¿Por qué? El sistema operativo se encarga generalmente de interactuar con el hardware como la pantalla, los discos, la red o la impresora. Las aplicaciones que instalas no hacen todo lo que parece que hacen . Sino que en muchos casos piden al sistema operativo que haga cosas, como mostrar una leyenda en la pantalla, o que grabe un dato en el disco. Por eso , no puedes instalar así porque sí una aplicacion Windows en una Mac o una aplicación de Mac en un Windows. En los casos en que existe la misma aplicación para más de un sistema operativo, generalmente es otra aplicación que el mismo proveedor de software implementa para cada uno de los sistemas operativos. Por eso cuando haces un download como Adobe Photoshop, te pregunta si quieres bajarlo para Windows o para Mac. Y en muchos casos hasta te especifica para qué versión del sistema operativo quieres la aplicación.
Maquinas Virtuales
Entonces tenemos claro que no puedes instalar una aplicación Windows en un Linux o una aplicación para Linux en una Mac.
¿Tenemos claro eso? ¿o no?
Habría una forma de lograrlo. Y aquí es donde llegan las máquinas virtuales. Así como Excel te permite usar planillas de cálculo o Adobe Photoshop te permite editar fotos, las máquinas virtuales son un tipo de aplicación que lo que hace es Simular el funcionamiento de una computadora. Entonces cuando instalas la aplicación «Máquina Virtual» estás en cierto modo instalando una computadora dentro de tu computadora.
Esa «computadora virtual» está aislada de tu sistema operativo, lo que hace que le puedas instalar a esa máquina cualquier otro sistema operativo. Entonces puedes tener un Windows en el que instalaste una máquina virtual y dentro de esa máquina virtual instalar un Mac OS o un Linux, y luego instalar aplicaciones para ese otro sistema operativo.
Es más, esa máquina virtual puedes, apagarla, prenderla , suspenderla. Y si luego de apagarla la prendes, las cosas estarán en el estado que las dejaste.
Aún si instalas el mismo sistema operativo que tienes (ejemplo instalar un Windows en una máquina virtual de una computadora que ya tiene Windows), te permite tener un entorno totalmente aislado, donde trabajes con seteando otros usuarios, otras prefrerncias de pantalla y otras normas de seguridad distintas de las de tu sistema operativo real.
Considera que puedes tener muchas máquinas virtuales así como puedes tener muchas planillas de Excel. Auí puede surgir una confusión porque a veces se le llama Máquina Virtual a la aplicación, y también se le llama Máquina Virtual a cada entorno que definas con su sistema operativo. Ejemplos de aplicacions de Máquina Virtual son VirtualBox (de Oracle) y VMWare. En realidad, esas aplicaciones son como «manejadores» de máquinas virtuales.
Por ejemplo, si trabajas con una diversidad de clientes, y cada cliente tiene diferentes versiones de los sitemas operativos y diferentes configuraciones, podrías tener una máquina virtual por cada cliente, sin que se te mezclen las configuraciones de cada uno con el otro, y que tampoco desconfigures nada en tu sistema operativo.
Y no necesitas tener una Mac para correr programas Mac.
Una Desventaja de las Maquinas Virtuales
Una desventaja de la máquina virtual es que cuando la defines debes especificar los recursos que utilizará y esos recursos serán exclusivos de esa máquina virtual. Por ejemplo, si tu computadora tiene 16 Gb, y creas una definición de máquina virtual de 4 Gb, cuando corras esa máquina virtual esos 4Gb de memoria no podrá ser usado por ninguna otra aplicación.
También te imaginarás que lo que corras en tu máquina virtual podría tener alguna desmejora en la performance comparada con la misma aplicación corriendo en una máquina real. Pero si usas máquinas con suficientes recursos, es aceptable la velocidad con la que corre. En muchos casos hasta se usa para correr juegos que demandan muchos recursos.
En el ejemplo de la máquina virtual de 4Gb en la computadora de 16Gb no podrás correr más de 4 máquinas virtuales a la vez. En realidad no podrás correr más de 3 porque necesitas memoria para tu propio equipo.
Pero pese a esto fue y es una solución muy aceptable que permite mucha flexibilidad. Particularmente trabajo con máquinas virtuales para muchos de los clientes de techstartingpoint, dado que cada cliente tiene en sus entornos instalados distintas versiones de sistemas operativos, distintas configuraciones y distintas aplicaciones.
Una aplicación o Muchas aplicaciones
En los ejemplos que mencioné las aplicaciones son autocontenidas. Es decir, instalar la aplicación es todo lo que necesitas para que funcione. Muchas de ellas funcionan sin tener conexión de internet, lo que nos estaría asegurando que no estarían usando algún recurso externo.
Aún en el caso del navegador , como Chrome, podrás pensar… si no tengo internet no funciona. No es así, el navegador funciona y te da un mensaje de error indicando que no tiene internet (esa es su función), pero lo podrías utilizar plenamente para revisar archivos locales como HTML.
No es ese el caso para la mayoría de las aplicaciones que existen en el mercado, principalmente en la web o para smart-phones. Pero para que la aplicación sea útil necesitarás otras aplicaciones que estén corriendo en algún otro lado que no sea tu computadora o smart-phone.
Por ejemplo, Piensa en la aplicación de Uber. Instalas una aplicación en tu celular. Pero para que encuentre un auto compatible con tu requerimiento, neceistas algo centralizado que esté monitoreando todos los autos disponibles y elija los que están cerca tuyo para mostrartelo. Esa parte la hace «otra» aplicación que no está en tu smart-phone.
Esa otra aplicación seguramente no será para Android o para iPhone sino que estaría corriendo en una o varias máquinas mucho más potentes a las que generalmete se le llaman servidores.
De hecho, esa otra aplicación no es UNA aplicación sino que serán un conjunto de aplicaciones especializadas, que hacen partes del proceso de encontrar un auto, calificar un chofer, controlar la seguridad (el login), o guardar los viajes realizados, o procesar los pagos. Muchas de esas cosas no están en la aplicación para Android o IPhone que te bajaste para usar Uber.
Entonces queda claro que gran parte de las soluciones que utilizamos constan de muchas aplicaciones que contribuyen a brindarte el servicio, y que habrá que instalar y tener corriendo en distintas máquinas, muchas veces en distintos sitemas operativos. En muchos casos, si una de esas aplicaciones falla y deja de correr, se detendría el funcionamiento de todo el sistema o al menos de cierta funcionalidad específica.
Es más, para mitigar la posibilidad de falla, muchas veces tienen corriendo répliicas de la misma aplicación. Y hasta aumentan la cantidad de aplicaciones que corren cuando tienen picos de pedido, como pudiera ser la necesidad de una tienda virtual, para el Dia de las Madres, o Navidad o cualquiera de ese tipo de fiestas comerciales.
Maquinas Virtuales y Muchas aplicaciones.
Como te darás cuenta, el trabajar con máquinas virtuales en vez de servidores reales facilitará la instalación o la decisión de agregar instancias de una aplicación según la necesidad. Por ejemplo, puedes instalar en muy poco tiempo simplemente copiando (o similar) varias máquinas virtuales y poniéndolas a correr en un servidor super potente. Eso sería mucho menos trabajoso que instalar un servidor con su hardware desde cero.
Además tendrías la posibilidad de usar tus recursos de acuerdo a la necesidad, replicando la parte de la aplicación que tenga más demanda y usando pocos recursos a la parte que no está siendo utilizada en este momento.
Por otra parte , piensa cómo debe ser el entorno donde esa solución se implementa, se modifica, se corrige, se prueba. Cuando quieres usar Uber, te bajas la aplicación Uber de tu smartphone para usarla y ya está.
Para los desarrolladores que la implementan no es tan sencillo. Cuando surje una falla o quieren implementar una mejora deben determinar en cual o cuales de las aplicaciones se debe hacer el cambio. Entonces los desarrolladores deben tener disponible, no solo la aplicación de smartphone, sino todas las aplicaciones que involucran la solución , o al menos simulaciones de ciertas aplicaciones para poder probar la solución completa.
Docker y sus ventajas sobre las máquinas virtuales.
Ya nos imaginamos una estrategia del equipo de desarrollo, implementando una solución que involucra varias aplicaciones. Podría ser tener una máquina virtual por cada aplicación o por cada conjunto de aplicaciones que se decida trabajar junta (en una máquina virtual también puedes instalar varias aplicaciones).
Pero nuevamente, la máquina virtual consume muchos recursos dado que cada máquina virtual debe contener una copia del sistema operativo que estará usando, además de contar con la potencia de memoria y cpu para ejecutarla.
Es por eso que antes de la existencia de los contenedores y containers, las empresas tengan datacenters con máquinas vituales. En muchos casos podrían tener un entorno completo, con todos los servidores (tal vez vitualizados) para cada instancia de desarrollo. Es decir, uno para que lo usen los desarrolladores, otro para que lo usen los testers una vez que el producto había sido implementado o el cambio realizado. Y existiría otro entorno que sería el que usan los clientes finales.
También nos vamos dando cuenta del trabajo que puede costar pasar de un entorno al otro, y mucho más, de volver atrás un cambio cuando algo sale mal.
No nos podemos imaginar con tales costos, proveer a cada desarrollador una máquina que tenga la potencia para correr todas las másquinas virtuales que componene la solución. En algunos casos, cuando lo ameritaba, las empresas les dan de alta en sus servidores alguna máquina virtual para un desarrollador específico. Pero lo más común debido a costos (y según el presupuesto de la empresa) era que todos los desarrolladores compartan un entorno. Lo que podía traer ciertos inconvenientes, cuando lo que el desarrollador arreglaba involucraba más de una de las aplicaciones que componían la aplicación.
Entonces vemos que las máquinas virtuales trajeron una ventaja, que fue generar un entorno «por programa» no necesitando un nuevo hardaware para instalarlo. No obstante, la ventaja real necesaria, no sería replicar el hardware como hacen las máquinas virtuales, sino que la real ventaja podría ser tener un entorno aislado.
Y esto es lo que vienen a brindar los containers como Docker.
Qué es Docker
Docker utiliza otra estrategia para conseguir el aislamiento del entorno, y tener algo parecido (un entorno) a una máquina independiente. Básicamente docker lo que hace es utilizar ciertas características del sitema operativo linux que permiten tener un alcance limitado y parcial del sistema operativo. Ese alcance limitado (que consiguen utilizando algo llamado namespaces) permite el aislamiento de todo lo que ocurra allí y la certeza de que no podrá usar nada de otro espacio. Entonces cada «container» de docker está trabajando con un entorno aislado.
Esto permite que en cada entorno aislado, instales distintas aplicaciones, settes distintas configuraciones o brindes distintos servicios. Hasta podrías instalar distintas versiones del sistema operativo principal.
Cuando defines una container en docker (parecido a definir una máquina virtual), especificas la configuración particular y las aplicaciones que instalas en esa máquina y hasta puedes especificar correr comandos como copiar este archivo aquí o allí y agregar esta carpeta.
Cuando corres docker, te generará por cada container un entorno que tenga todas las cosas que definiste se deberían instalar en ese entorno, como pudiera ser un motor de Base de Datos, un Servidor Web, o tu propia aplicación.
Pero todo esto es una simple definición. Esa definición que consta de algunos comandos, en general se guarda en un archivo llamado Dockerfile.
Para preparar la máquina, docker provee una opción de hacer un «build». Lo que hace el build básicamente es conseguir todos los programas o libraries que definiste instalar, Y termina construyendo lo que en Docker se llama una Imagen.
Si bien está toda la información en el DockerFile, el «armado» de la imagen permite no tener tiempos de espera largos cada vez que levantas una máquina. Imaginate que tu máquina tenga un servidor web y un servidor de base de datos, la espera que se requiere para descargar esas aplicaciones así como para instalarlas no habrá que esperarlas si la imagen fue generada previamente.
Entonces al ejecutar una imagen de docker comienza a correr un entorno aislado llamado Container (que es básicamente la imagen ejecutandose).,
Puedes correr muchas veces una imagen, que es como el template y tener varios containers replicados corriendo.
Otra ventaja, es que existe un repositorio de imagenes que es libre y del cual te puedes bajar imágenes de Docker con ciertas soluciones, como pueden ser WordPress, Jenkins, Ubuntu, Web servers y muchos más . El repositorio principal es Docker Hub y también podrias armar tu repositorio en tu empresa.
¿Y qué hay de los recursos?
Lo importante en Docker es la definición del entorno, no el contenido. El contenido es tuyo. A diferencia de las máquinas virtuales, que cuando las apagas conservan una foto del último momento que las usaste y cuando las prendes retomas desde allí, en Docker, cada vez que corras una imagen desde cero empezarás desde su definición.
A diferencia de las máquinas virtuales, Docker no corre un sistema operativo virtual completo, sino que corre en una parte aislada de tu propio sistema operativo, usando los recursos de este.
Esto hace la solución mucho menos pesada. Si tienes un Docker container que le asignes 4Gb, podrías usar más de 4 containers docker a la vez aún si tu máquina física tiene sólo 16 Gb. (siempre y cuando los containers no usen todos los 4 Gb a la vez)
VOLUME in Docker
También hace que sea (levemente) más compleja la forma de definir el área de datos que quieres que trascienda los containers. Por ejemplo, pudieras decidir que los datos de una base de datos sean persistidos en un área fuera del container o de la imagen de docker. Entonces cuando otro usuario trabaje con esa definición de imagen, no estará usando los mismos datos. La técnica más utilizada de definir estas secciones de datos es mediante VOLUME. En general en el DockerFile defines con VOLUME una relación entre el «nombre del VOLUME» y una carpeta dentro del container. Recordemos que el Dockerfile es una forma de definir una Imagen de docker. Y al momento de correr el container («docker run….»), defines mediante -v (VOLUME) la relación entre una carpeta en tu host (el equipo principal) y el nombre del volume que definiste en el DockerFile. Esto hace que puedas «compartir» una carpeta de tu host dentro del container. Es decir que el docker container en ejecución use directamente esa carpeta del host. Queda claro que los datos que estén allí no quedan dentro de la imagen ni del container ni de la imagen.
Otras ventajas de Docker
Una gran ventaja por sobre las máquinas virtuales es que puedes tener muchas instancias de container Docker sin tener repetido el sistema operativo. Entonces es mucho más liviano y consume sólo los recursos necesarios.
Como vimos antes cuando defines una máquina virtual con cierta cantidad de memoria, esa memoria sera exclusiva de la máquina virtual mientras se ejecute sea que la esté «usando» o no.
Esto permite que ahora sea posible instalar en la máquina virtual las muchas aplicaciones que requiere una solución y que cada desarrollador tenga su propio entorno que no afecte el entorno de los demás.
Otra ventaja, es la formalización de cómo se define un entorno. En el caso de las máquinas virtuales, (como pasa en tu máquina), no se guarda una historia de todo lo que haces, como cambiar una configuración o instalar una aplicación. Simplemente se cambia el estado.
Instalas una aplicación, queda la máquina virtual con la aplicación instalada. Desinstalas la aplicación: queda la máquina virtual sin esa aplicación. Pero no guarda un registro histórico de todo lo que pasó en esa máquina luego de su creación.
En docker todo lo que queda instalado (que consideras importante) está en la definición. Entonces puedes mirando la definición saber qué software está instalado y cómo fue modificado el entorno original.
Esto facilita el deploy (deploy es lo que mencioné antes de pasar de un entorno de desarrollo a uno de testing , o pasar de un entorno de testing al que usa el cliente final)
También es mucho más fácil aún si todos los entornos usan docker. Porque en cierta manera te «obliga» a formalizar las cosas que realmente neceistas en la definición.
En cuanto a los sistemas operatvos, si bien no tienes la flexibilidad que te brindan las máquinas virtuales, puedes obtener resultados muy parecidos.
De hecho, Docker utiliza el sistema operativo y los recursos de la máquina principal . Pero puedes utilizar una versión diferente del mismo sistema operativo dentro del Docker container. Y aún en el caso de que necesites otro sitema operativo puedes solucionarlo tan fácil como instalando docker dentro de una máquina virtual que tenga el sistema operativo que necesites.
Al ser más fácil el deploy, también es más fácil agregar o quitar instancias de una de las partes de la solución.
Docker y MicroServicios
Otra ventaja adicional es que siendo tan poco costoso, deployar, administrar, crear, replicar instancias de Containers, sea muy utilizado en entorno de arquitecturas micrservicios.
Un entorno de arquitectura de microservicios se refiere a generar una solución practicamente con una aplicación por cada servicio que brinde. Por ejemplo en Excel podemos crear una planilla, calcular una fórmula, borrar una celda, copiar una fila, todo con una sola aplicación ejecutable. Si bien la experiencia del usuario podría ser similar, se pude implementar por detrás con una aplicación con su entorno por cada servicio que la solución brinda. Una aplicación que solo copia celdas, otra que solo crea una planilla y así sucesivamente.
Si bien pareciera que se añade complejidad, el costo de tener una aplicación distinta para cada cosa no añade complejidad a la solución total. Por otra parte si una parte del sistema anda mal o debe ser mejorada, se puede deployar sólo esa parte y no toda la aplicación.
También, si por ejemplo durante Navidad o el Dia de la madre o cualquier otra fiesta comercial hay picos de «ventas» se puede replicar generar muchos containers dockers que acepten ventas sin necesidad de replicar la aplicación completa que puede incluir suscribirse a notificaciones o cualquier otra funcionalidad no tan utilizada esos días. Esto implica usar los recursos de una manera mucho más racional. Y como docker está estandarizado es mucho más fácil automatizar estos cambios de acuerdo a condiciones que se definan.
Docker , Docker Compose, Docker Swarm y Kubernetes
Hasta ahora vimos cómo podemos mediante docker definir un entorno que se ejecute dentro de nuestro sistema operativo como si fuera una máquina aislada.
Como vimos la definición estaría plasmada en un Dockerfile. Ese Dockerfile tiene los elementos suficientes para levantar una máquina Entonces con varios Dockerfile podríamos definir varias máquinas. Es mas. con un solo Dockerfile, podríamos hacer que se corra ,más de una máquina si los levantamos múltiples veces.
De acuerdo con este escenario, podríamos tener corriendo varios containers, (o máquinas «virtuales») en nuestro equipo. Si necesitamos una combinación de containers corriendo, y siempre esa combinación es la misma o tiene leves modificaciones, podemos simplificar su administración y definición mediante otra herramienta que es docker-compose.
docker-compose nos permite definir la corrida (el docker run) de uno o varios Dockerfile o de varios Docker Images en un equipo. Hasta mediante configuración podemos definir cuantas instancias de cada container queremos correr o definir la relación entre ellos, simplificando la corrida de varios containers en el mismo equipo.
Otra herramienta que nos permite aún más versatilidad es Docker Swarm. Básicamente permite configurar un conjunto de Containers que deben correr en un entorno distribuido. Sería similar a docker-compose pero en cambio de correr en un solo equipo, puede correr containers en varios equipos, y también monitorearlos, y controlarlos. Entonces podríamos tener Containers en AWS, Google Cloud, Azure o nuestros equipos combinados corriendo siendo monitoreados y controlados por Docker Swarm.
Kubernetes es otra alternativa que tiene funciones similares a Docker Swarm. Vemos que lo que antes era instalar, mantener y monitorear un centro de cómputos, ahora se puede hacer con herramientas open source, gratuitas, y con solo unos pocos archivos de configuración.
Dado que estas soluciones son standard, es fácil mover entornos de un lugar a otro. Y estas definiciones tienen tal formalidad que hacen que si algo anda en un entorno es muy probable que ande en otro, y sería relativamente fácil identificar por qué algo está fallando. Esto es debido a que toda la topología de nuestros equipos estaría definida en un lugar central que son las definiciones de nuestro containers o de las otras herramientas que nos ayudan a administrarlos.
Por qué Docker usa Containers
La idea de llamar Containers a la solución nace de la solución que se adoptó para transportar cosas en los barcos. La utilización de Containers facilita el transporte y la manipulación de cualquier tipo de mercancía a los que lo único que tienen que hacer es transportarla de un lugar a otro.
Entonces, los que trabajan en la logística de los barcos no necesitan especialización para cada tipo de mercadería. Lo que hacen es subir containers al barco, bajarlos, subir containers al cambio , entregarlos, devolver los containers vacíos.
Lo mismo pasa con Docker, son instancias de entornos aislados, Si bien las máquinas virtuales cumplen con esta característica, en el caso de Docker (y los productos denominados Containers), logran el mismo aislamiento con mucho menos recursos. Y también pueden ser manipulados de una manera standard.
No solo eso, sino que al ser standard, ya hay disponibles herramientas y tecnologías para manejarlos de manera sencilla como puede ser Kubernetes y Docker Swarn. A estas tecnologías a veces se las llama «orquestadores» que facilian la administración de varios containers.
También las empresas que proveen servicios en la nube, tango Azure, como Google como Amazon, y otras principales, brindan servicios directamente que admiten subir contenedores. (También brindan servicios de máquinas virtuales en la nube).
Por eso, gracias a los containers, cada vez será menos utilizado como excusa el caso en que un cliente reporte un error, y el desarrollador le conteste: «A mi me anda»