Contenedores: una opción para facilitar el desarrollo de software de forma efectiva

En el año 2003 o 2004 empecé a conocer las teconologías de virtualización, gracias a un compañero que me habló del tema y de los productos de VMware, los cuales para su momento me parecieron muy buenos y me permitieron practicar y aprender varias tópicos. Pasado algún tiempo conocí el software VirtualBox, el cual ha sido muy práctico y funcional para mi flujo de trabajo, especialmente como desarrollador de software.

Luego, entre 2013 y 2014, conocí Vagrant, un software muy bueno que me facilita la creación, configuración y destrucción de ambientes de desarrollo; ambientes que se declaran en un archivo de texto, el cual a su vez puede incluirse en un software de control de versiones, ya sea para compartir esos ambientes con otros desarrolladores o para desplegarlos en otros equipos de cómputo, con lo que se economiza tiempo y esfuerzos para contar con ambientes reproducibles y automatizables, especialmente en el ámbito de pruebas de software, lo que en último caso contribuye a elevar la calidad del software que se está creando (o al menos esa es la intención).

Uno de los conceptos existentes en la forma de trabajo de Vagrant es el de proveedores, los cuales son los caballos de batalla que en realidad ponen a disposición esos ambientes, siendo VirtualBox mi proveedor preferido, o al menos así fue hasta que empecé a experimentar con las tecnologías de contenedores (o containers, como se les conoce en inglés).

Antes de entrar al tema de los contenedores, me gustaría destacar lo que no me gusta de trabajar con máquinas virtuales como proveedoras de ambientes de Vagrant: se desaprovecha mucho tiempo valioso, producto de perder la concentración, mientras se espera que Vagrant despliegue uno o más de esos ambientes. Cuando uno está desarrollando software es importantísimo mantener el hilo mental de lo que se está creando, del problema que se intenta resolver o del error que se quiere depurar, así que una espera de unos 3 o más minutos puede romper ese delgado hilo y alargar el tiempo total requerido para ejecutar una actividad, sobretodo si esos ciclos de espera se repiten varias veces durante una jornada determinada. ¿Y cuál es la razón de esto? La respuesta es sencilla: se paga un precio muy alto por mantener esa virtualización andando, dado que la misma recrea varias capas: una para la abstracción del hardware, otra para un sistema operativo completo y sobre ambas la capa que de verdad se necesita para el software que se está desarrollando (bibliotecas, datos, entornos de ejecución para determinados lenguajes de programación, etc). Y ese precio se paga principalmente en tiempo de desarrollo y en rendimiento: entre más máquinas virtuales estén ejecutándose a la vez, obviamente mayor es la degradación del rendimiento del sistema anfitrión, a veces hasta niveles imprácticos, incluso teniendo un hardware relativamente moderno y potente. ¿Y qué tal si esa virtualización pudiera eliminarse por completo al momento de proveer ambientes de desarrollo? Allí es donde entra la tecnología de contenedores...

Durante una década he conocido superficialmente la existencia del concepto de contenedor, el cual resumiría intuitivamente como "un sistema operativo encerrado dentro de otro sistema operativo, limitado al uso de ciertos recursos y bajo ciertos privilegios definidos en el sistema operativo anfitrión que lo contiene", sin embargo ha sido en el año 2014 que me topé con Docker, una tecnología basada en contenedores, rodeada de un ecosistema y una plataforma que la han puesto en boga, logrando capitalizar lo que otras tecnologías similares y pioneras en el área no han podido capitalizar. Pero se acabó el 2014 y en lo único que avancé fue en la parte conceptual que sustenta a Docker. Luego, en febrero de 2015 llegó a mis manos un requerimiento puntual para resolverlo con contenedores basados en Docker, así que me dije "aquí está la oportunidad apropiada para ponerme manos a la obra". ¡Y así ha sido!

Resumo mis impresiones principales logradas al trabajar inicialmente con la versión 1.5 de Docker:

  • Docker requiere un procesador Intel o AMD de 64 bits con un sistema operativo de 64 bits. El computador que utilicé tenía Ubuntu 14.10 de 32 bits con un procesador de 64 bits, por lo que tuve que reinstalar dicho sistema operativo usando su versión de 64 bits.
  • Las tecnologías de contenedores en general, y Docker en particular, sólo sirven para contener a sistemas operativos de la misma familia; es decir, un sistema operativo con kernel Linux (cualquiera sea la distribución) conteniendo a otros sistemas operativos con ese mismo kernel (también cualquiera sea la distribución). Esto a mi no me afecta porque en los equipos de cómputo que utilizo, el sistema operativo ejecutado es GNU/Linux (principalmente Ubuntu o Debian) y desarrollo para plataformas de ese mismo tipo.
  • Docker requiere una versión reciente del kernel de Linux (3.16 es la que estoy utilizando en estas primeras prácticas)
  • La versión de Docker presente en los repositorios oficiales tanto de Ubuntu como de Debian no es la más reciente y dado que Docker está en plena evolución, es más conveniente utilizar el repositorio alternativo que se detalla en la documentación oficial para la instalación.
  • Los tres componentes de principales de Docker son: el servicio docker (docker daemon), el cliente docker (interfaz de línea de comandos) y el registro donde se publican las imágenes que luego se utilizarán para crear los contenedores en el equipo local. Tanto el servicio como el cliente son parte de un mismo ejecutable (en Ubuntu su ruta es /usr/bin/docker) sólo que de acuerdo a los parámetros que reciba se comporta de un modo u otro; el servidor puede “escuchar” tanto por un socket UNIX como por un puerto TCP y brinda dos interfaces: una para ejecución de comandos y la otra es una API RESTful (HTTP o HTTPS). Es posible crear una cuenta en Docker Hub para subir imágenes públicas a Internet, aunque también puede desplegarse un registro privado (por ejemplo dentro de una Intranet), sin embargo la interfaz web que usa el registro público no está disponible.
  • Para aprovechar Docker es prácticamente obligatorio contar con conexión a Internet (mientras mayor sea su velocidad mucho mejor), puesto que es frecuente descargar imágenes de sistemas operativos previamente construidas y disponibles en el repositorio público de Docker. Esas imágenes pueden ser "oficiales" (revisadas y avaladas por la gente del equipo de Docker o sus asociados) o proveídas por la comunidad (sin revisiones formales, sin garantía alguna). Luego de descargadas las imágenes es posible trabajar sin conexión a Internet, puesto que los contenedores que posteriormente se crean en base a esas imágenes sólo requieren que la capa esté almacenada localmente (si el contenedor requiere la instalación de software adicional desde alguna fuente externa, no queda otra que conectarse a Internet).
  • ¡Usar contenedores de verdad implica un rendimiento muy rápido! Si hacemos la comparación con el uso de máquinas virtuales estamos hablando de tiempos de espera en minutos que se reducen a muy pocos segundos (menos de 5) o milisegundos. Nota: esta comparación es válida sólo después que se ha descargado la imagen del sistema operativo desde el repositiorio de Docker en Internet y a partir de la cual se creará el contenedor.
  • El rendimiento general del equipo anfitrión es muchísimo mejor, puesto que se deslastra de dedicar recursos (especialmente memoria RAM y CPU) para mantener en ejecución una o más máquinas virtuales.
  • El uso de espacio en disco o almacenamiento secundario no se desperdicia. Si creo dos contenedores basados en dos imágenes totalmente diferentes pues se requerirá almacenar ambas imágenes totalmente; pero si los contenedores están basados en la misma imagen sólo se requerirá el espacio para una sola imagen. Cabe destacar que esas imágenes están construidas en base a "capas" de sólo lectura en el sistema de archivos, que se montan unas sobre otras y donde cada capa cuenta con un identificador único que evita su duplicidad; luego, cuando se crea un contenedor lo que Docker hace es agregar "encima" una capa más, pero esta vez de lectura-escritura para constituir un espacio de trabajo.
  • La filosofía de despliegue de una aplicación al utilizar Docker es muy diferente a lo que regularmente he aplicado. Por ejemplo, en vez de contar con un equipo (físico o virtualizado) en el que se instala el sistema operativo, el servidor de bases de datos, el servidor web y la aplicación como tal, con Docker lo recomendado es contar con un equipo (físico o virtualizado) ejecutando el servicio docker (docker host) el cual a su vez provee varios contenedores: un contenedor basado en determinado sistema operativo cuyo único proceso en ejecución es el del servidor de bases de datos, otro contenedor basado en determinado sistema operativo cuyo único proceso en ejecución es el del servidor web y otro contenedor basado en determinado sistema operativo para proveer el volumen de datos en el que está la aplicación como tal y finalmente varios enlaces entre esos contenedores según sea necesario.
  • Con Docker o con otras tecnologías de contenedores se me facilitará mantener el mínimo de paquetes de software instalados y de servicios en ejecución en mi equipo de uso habitual. Si necesito desarrollar una aplicación nueva o experimentar con un nuevo lenguaje de programación, lo que convenientemente puedo hacer es crear un contenedor sobre el que instale sólo el software necesario para mi propósito, enlazado a un volumen en el que está el código fuente que tengo bajo control de versiones y de ser necesario con un segundo enlace a otro contenedor en el que tenga algún gestor de bases de datos. Luego que alcance el objetivo que me haya propuesto y con el código fuente versionado lo que hago es destruir el contenedor o contenedores utilizados y ¡listo!

Ahora, no todo en Docker es color de rosas; también viene con sus puntos en contra:

  • En el sistema operativo anfitrión (docker host) se requiere privilegios de súper usuario (root) ya sea directa o indirectamente (con sudo o agregando la cuenta de usuario a un grupo privilegiado) para ejecutar todos los comandos de docker (cuando digo "todos" son "todos"). En mi ambiente de desarrollo, dentro de una Intranet, protegido por un cortafuegos, el riesgo de sufrir un ataque tal vez sea pequeño, pero al desplegar una solución en un ambiente de producción, sobre todo si fuese algo que se expondría en Internet, el asunto cambia y requerirá mayor estudio y pruebas. También sucede que el usuario utilizado dentro de los contenedores es el súper usuario (al menos así es con las imágenes con las que he trabajado)
  • La parte de direccionamiento de red entre el anfitrión y los contenedores siempre es dinámica y cambia cada vez que un contenedor se inicia. Asignar una dirección estática IPv4 no me fue posible (hay un procedimiento no oficial que leí en algún lado según el cual eso es factible, pero me pareció muy complicado, así que no lo apliqué)
  • No me queda claro hacia dónde quiere ir la empresa Docker Inc, promotora principal de la plataforma Docker. Esto porque habiendo Docker Inc basado su auge y éxito en LXC, un proyecto pionero ya existente y menos famoso para trabajar con contenedores y que apunta a lograr una estandarización de estas tecnologías, recientemente lo que hizo fue quitar el formato de ejecución de LXC como el predeterminado al momento de crear un contenedor y en su lugar ha puesto su propio formato denominado "libcontainer". Esto no necesariamente es algo negativo, pero preferiría la adopción de algún estándar de contenedores a "quedar amarrado" a lo que Docker Inc implemente.

Bueno, después que obtuve el mínimo necesario de experiencia práctica con Docker, volví al asunto que desde el punto de vista de desarrollador de software me interesa: ¿cómo proveerme ambientes de desarrollo y pruebas aprovechando Vagrant y Docker? Realmente esto es sencillo y en la documentación de Vagrant para utilizar Docker como proveedor, está lo fundamental para arrancar y practicar. Después que interactué con ambas tecnologías concluyo que esta es la vía que me otorga mayores beneficios y productividad y que en adelante voy a seguir y trataré que las personas con las que participe en proyectos de desarrollo de software también se beneficien.

Finalmente, este es el panorama (muy posiblemente incompleto) que logro vislumbrar sobre el mundillo de las tecnologías de contenedores, existente desde hace un buen tiempo y en el que Docker ha servido de catalizador para que "las masas" lo conozcan y lo aprovechen y que independientemente de cuáles tecnologías puntuales logren posicionarse, muy seguramente su adopción en los centros de datos y de cómputo se hará realidad:

  • Hay una puja interesante y en pleno desarrollo por liderar el sector. Con Docker no observo algo nativo para orquestar contenedores (en las pruebas que hice sólo pude comunicar contenedores alojados dentro de un mismo anfitrión físico o virtual y todavía no he experimentado con Docker Swarm) ni tampoco alguna especie de gestor de los procesos que deberían estar ejecutándose dentro de los mismos, por lo que CoreOS, una nueva distribución de Linux basada en tecnologías de Google y que presenta una propuesta interesantísima de un sistema operativo distribuido, seguro y siempre actualizado, constituye una clara alternativa y competencia a lo que propone Docker Inc, puesto que además de soportar el formato de contenedores de Docker, en diciembre de 2014 ha sacado su propio proyecto de contenedores, llamado Rocket. A esto podemos sumar los también interesantes proyectos promovidos por Canonical (creadores de la distribución Ubuntu): LXD (hipervisor de contenedores) y Snappy Ubuntu Core (despliegue de contenedores en la nube), además de las iniciativas que pudieran estar llevando otros actores del sector tecnológico.
  • El enfoque DevOps para desarrollar software se apalanca con el uso de contenedores, haciendo cada vez más débil a la línea que separa a los “programadores” de los “operadores” del área tecnológica de las organizaciones. A mi en lo particular esto me gusta, porque así la ejecución de los proyectos fluye de mejor manera y en menor tiempo.
  • Incluso para el mundo de los productos de Microsoft existen o se están promoviendo propuestas que aprovechan las tecnologías de contenedores: Drawbridge y Spoon son dos ejemplos de ello.

Añadir nuevo comentario