En recientes fechas se nos encomendó la misión de optimizar costos y el uso de recursos de Amazon Web Services utilizados para el despliegue y operación de aplicaciones de uno de los clientes principales de InnBit.
Esta reestructura fue vista como una oportunidad para implementar mejoras en la forma de trabajo con AWS que habíamos estado teniendo. Un punto muy particular es el aprovisionamiento de ambientes que implica lanzar una nueva instancia de EC2, actualizar paquetes, instalar dependencias, configurar el ambiente y desplegar la aplicación para dejar todo listo para que esté disponible para su uso.
Todos los pasos descritos con anterioridad son repetitivos y son propensos a ser automatizados por lo que se decidió incluir la herramienta Ansible para facilitar las tareas de aprovisionamiento y despliegue así como reducir posibles errores y el tiempo que se empleaba para poner a punto las aplicaciones.
Ansible
Ansible es una herramienta de código abierto escrita en python para la automatización y orquestación de tareas
A diferencia de otras soluciones similares, no requiere la instalación de agentes remotos pues su funcionamiento es mediante la ejecución remota de comandos mediante mecanismos como ssh o Windows Remote Managment.
Los comandos son definidos en archivos de texto en formato YAML y permite realizar ejecuciones de comandos repetibles y distribuidas en varios nodos.
Caso de uso
Durante 2016 se desarrollaron aplicaciones que estuvieron en producción casi todo el año. Cuando concluyó este, dichas aplicaciones también terminaron su ciclo debido al fin por el cual fueron construidas. Aún así el cliente solicitó que se mantuvieran activas para fines demostrativos.
Por ciertas razones, en su momento se reservó una instancia EC2 con las siguientes características
- Red Hat Enterprise Linux
- Reservada hasta el 20 Junio de 2017
- t2.medium
De acuerdo a los datos de uso y pruebas, se estima que esta instancia sería capaz de manejar de 3 a 4 aplicaciones con baja demanda. De este modo se determinó que la instancia RHEL sería aprovechada para hospedar las aplicaciones con propósito demostrativo.
Para facilitar la configuración y puesta en marcha de varias aplicaciones en un mismo servidor se decidió generar imágenes docker con cada una de las aplicaciones. Estas imágenes serían almacenadas en el registro de contenedores de EC2 (EC2 Container Registry, ECS) donde estarían disponibles para la ejecución de contenedores.
Otro beneficio de utilizar docker es el redireccionamiento de bitácoras. Anteriormente, para revisar una bitácora era necesario ingresar al servidor y explorar los archivos mediante comandos de Linux para procesamiento de texto. Conforme se incrementa el número de servidores y la incorporación de servidores surge la necesidad de concentrar las bitácoras en un solo punto de modo que la detección de errores y solución de problemas sea más ágil.
Docker ofrece un controlador que permite captar la bitácoras generadas por las aplicaciones dentro de los contenedores y enviarlas al servicio CloudWatch el cual incorpora una funcionalidad para concentrar bitácoras y explorarlas.
Todo el proceso desde la instalación de dependencias hasta la ejecución de las aplicaciones en forma de contenedores fue definido mediante un proyecto Ansible quedando el panorama como se muestra en la imágen.
Proyecto Ansible
Para intentar mantener ordenado y simple el proyecto, se ha organizado de la siguiente manera.
Inventario y Archivos de recursos
El inventario es el archivo de nombre hosts, el cual contiene un grupo de servidores con la ubicación de la instancia RHEL en Amazon.
En la carpeta resources/yum se guardan definiciones de repositorios para instalar los paquetes nginx y docker de acuerdo a la documentación de ambos productos. La idea es que estos archivos sean copiados, utilizando Ansible, a la instancia remota en la ubicación adecuada.
En la carpeta resources/env se guardan archivos con las variables de ambiente requeridas por las aplicaciones. En este punto se pretende nuevamente copiar estos archivos de configuración al servidor y leerlos mediante docker al momento de lanzar los contenedores.
Playbooks
Los playbooks son archivos en formato YAML donde se definen todos los comandos que serán ejecutados en el servidor.
Se separaron las tareas de instalación y configuración de acuerdo al paquete y/o aplicación para mantener compactos los archivos.
nginx.playbook.yml. Instalación típica de NGINX para RHEL, en este caso se utilizó ansible para copiar el archivo ./resources/yum/nginx.repo con la ubicación de paquetes actualizados para la instalación.
awscli.playbook.yml. Instalación de la linea de comandos de AWS. Este se utilizará para la interacción con EC2 Container Registry.
docker.playbook.yml. Instalación y configuración de Docker de acuerdo a la documentación oficial. De igual modo que el anterior, se actualizó la definición de repositorios mediante el archivo ./resources/yum/docker.repo que es copiado al servidor para posteriormente realizar las tareas de actualización de paquetes. Al final se genera el grupo docker y se define al usuario ec2-user como miembro de modo que pueda ejecutar comandos docker sin permisos de super usuario.
cop13.playbook.yml. Ejecución de contenedor docker a partir de una imagen alojada en EC2 Container Registry. Esta imágen contiene una aplicación Ruby on Rails que será ejecutada en el puerto 3000 del contenedor. Mediante ansible, además de lanzar el contenedor, también se establece la correspondencia de puertos (3000:3000), el archivo con las variables de entorno requeridas y el redireccionamiento de bitácoras a CloudWatch.
igf.playbook.yml. Ejecución de un segundo contenedor docker a partir de otra imagen alojada en ECR. La ejecución del contenedor es similar al anterior con pequeñas diferencias como la imagen que se toma, el puerto del servidor que se redirecciona al contenedor (3100:3000), las variables de entorno y el destino de bitácoras dentro de CloudWatch.
rhel-demo-server.playbook.yml. Este archivo incluye referencias ordenadas a los demás archivos de modo que permite mantener la secuencia lógica con las cuales se van a ejecutar las instrucciones.
Conclusiones
Al final los archivos de ansible permitieron la puesta en marcha de las aplicaciones partiendo de una instancia nueva de EC2. Como ventaja estos archivos permiten la replicación automatizada de este ambiente en nuevas y diferentes instancias.
Estos scripts también son propensos de ser incluidos en un conducto de entrega y despliegue contínuo, pero será tema de otra entrada del blog.