¿Estás listo para el despliegue? - Consideraciones prácticas de los deployments

2 de enero de 2019

Hace poco, tanto en Pixmat como en IFARHU hemos tenido que planear la puesta en marcha y ejecución de algunos proyectos de software que hemos estado trabajando desde hace algún tiempo.

En mi concepto, el deployment (despliegue) no inicia en el momento en que realizamos la ejecución del código en el ambiente, sino que es probable que sea una de las fases más avanzadas de este proceso, el cuál debe iniciar con la planeación de la arquitectura de nuestra aplicación.

En este post intentaré desmenuzar algunas buenas prácticas que he podido recopilar por experiencia propia, que puede sean útiles para muchos.

#.1. Asegúrate siempre de utilizar un Sistema de Control de Versiones

Este punto es bastante obvio, pero igual es importante recordarlo. Utiliza Git o cualquier otro sistema de control de versiones (CVS).

Git es el más utilizado hoy en día y hay sistemas, basados en Git, que hacen tu vida más fácil, como:

#.2. Twelve-Factor App

Como lo dije inicialmente, el deployment debe verse como un proceso, en donde la arquitectura del sistema juega un papel dentro del mismo.

Twelve-Factor App es una “metodología” para fabricar aplicaciones de tipo SaaS. Yo lo veo más como una serie de recomendaciones, tal como lo indica el texto original:

"Our motivation is to raise awareness of some systemic problems we’ve seen in modern application development, to provide a shared vocabulary for discussing those problems, and to offer a set of broad conceptual solutions to those problems with accompanying terminology."

Consta de doce principios, los cuales enuncio y doy un ejemplo por cada uno de ellos:

  1. Codebase: Manten un branch (ver punto 1) por cada ambiente. Recomendaría incluso implementar algún sistema de branching como git-flow.
  2. Dependencies: Utiliza Maven (Java), NPM / Yarn (JavaScript), Composer (PHP), Bundler (Ruby) o cualquier otro sistema similar, pero separa las depdencias de tu código fuente. Siempre.
  3. Config: La configuración no debe estar en el repositorio, jamás. ¿Tienes las contraseñas de la Base de Datos en el Git? Comenzaste mal. Utiliza dot env (disponible en varios lenguajes) o utiliza variables de entorno.
  4. Backing services: Los servicios agregados (Base de Datos, un Message Queue, etc.) deben ser tratados como servicios independientes (pero vinculados al proyecto, como si fuesen dependencias).
  5. Build, release, run: Mantener el proceso de despliegue bien estructurado, además de distintos ambiente (para distintas fases del proyecto).
  6. (Stateless) Processes: Las aplicaciones no deben tener estados ni compartir los mismos con otras partes del aplicación (para eso deberían existir las Bases de Datos, por ejemplo). La aplicación debe verse como un proceso único.
  7. Port binding: La aplicación debe ser “auto-contenida”. Es decir, deben utilizar un protocolo (como HTTP) para hacerse público, mediante la asignación de un puerto específico.
  8. Concurrency: Piensa siempre en el escalamiento de tu aplicación (veremos más tarde algunso puntos sobre esto).
  9. Disposability: Asegúrate que si se reinician tus servicios, no explote algo. Un error muy común es ejecutar tareas muy pesadas en primer plano, a través del protocolo HTTP (cuando hay otras formas más correctas de hacerlo).
  10. Dev/prod parity: Desarrollo, stage, producción deben ser tan similares como sea posible. Esto ayuda a detectar posibles fallos o, incluso, a poder replicar los mismos. Lo más importante es que puedas probar con un sistema lo más parecido a producción posible.
  11. Logs: Otro error muy común es no tratar los logs como streams de eventos. Voy a tratar esto más adelante.
  12. Admin processes: Lee el punto de Disposability. Esta es una forma de corregir el ejemplo dado. Los procesos deben ejecutarse fuera / independientemente.

#.3. Asegúrate de tener pruebas (y automatizarlas)

Otro elemento bastante obvio, pero es importante tener en cuenta es que tu sistema debe contar con distintas capas de pruebas automatizadas.

El alcance de las pruebas es materia de un post totalmente distinto, pero creo que es importante también recalcar que:

  1. Ten distintos ambientes, tal como lo indica el punto anterior, para distintas fases del proyecto.
  2. Al menos ten tres ambientes: local (desarrollo), pruebas, producción. Puedes tener más, pero al menos asegurate de tener siempre estos tres.
  3. Todos los ambientes deben asemejarse lo más posible. Incluso, diría que deben ser lo más similares a producción. Hoy con herramientas como Docker, Kubernetes o Vagrant debe ser imposible decir “funciona en mi máquina”.
  4. Nunca, nunca, pero nunca. Nunca envíes a producción nada que no haya sido probado exhaustivamente en los otros ambientes.
  5. No te apures a entregar en producción.

#.4. CI / CD

Sumado con el punto anterior, es útil poder contar con un sistema de Integración Continua (CI) y un sistema de Entrega/Despliegue Continuo (CD) que facilite el proceso de realizar las pruebas automáticas y el despligue automático a los distintos ambientes.

Hay distintas herramientas que puedan ayudarte con esto, recomendaría a Jenkins, Bamboo y GitLab.

#.5. Puede fallar. ¿Estás preparado?

Como lo dijo el Ingeniero Aeroespacial, nacido en Panamá (zonian), Edward Murphy Jr. en las leyes que llevan su apellido: “Si algo puede fallar, fallará”.

El problema muchas no es solamente que falle, el problema es que debemos estar preparados para ello.

  • Recuerda los logs, para todo (con énfasis en lo que puede ir mal).
  • Si falla, asegúrate de recolectar toda la información posible.

Te recomiendo utilizar herramientas como Splunk, New Relic, Sentry o BugSnag.

#.6. ¿Escalaría horizontalmente? Centraliza los logs, caché y sesiones, archivos

Siempre piensa en que tu sistema puede o podrá crecer y cuando esto llegue a ocurrir, debes asegurar que el sistema permita el crecimiento.

Asegúrate de cumplir, con mayor importancia, algunos puntos tratados en el Twelve-Factor App, al centralizar partes del sistema.

Para los que no conocen el término “escalar horizontalmente”, quiere decir que debemos asegurarnos de poder contar con distintos servidores de aplicación que puedan distribuir la carga entre ellos (usualmente con un balanceador de carga, como HAProxy, delante).

#.Logs

No guardes los logs en archivos cuando puedes tratarlos como fuentes de eventos.

Además de las herramientas para detectar fallos en tu sistema, descritas en el punto anterior, te puedo recomendar otra herramienta que utilizamos mucho en Pixmat y es GrayLog.

GrayLog permite centralizar y administrar todos los logs, de distintas plataformas y sistemas. A través de esta plataforma usualmente monitoreamos las bitácoras de:

  • Servidor Web (Nginx o Apache)
  • Servidor de Base de datos
  • Logs de los sistemas / plataformas

#.Caché y Sesiones

No guardes la sesión en archivos únicamente dentro del servidor. El problema con esta práctica es, si escalas horizontalmente, tus sesiones solo permanecerán en uno de los servidores y no podrían ser utilizados por el resto de los servidores. Lo mismo ocurriría para el caché.

La solución más simple para ambos casos es utilizar Redis. Tanto en Pixmat como en IFARHU utilizamos Redis (tanto AWS como Azure, respectivamente, tienen servicios de Redis).

También utilizamos Redis como message broker, aunque en algunos casos utilizamos servicios específicos como RabbitMQ.

#.Archivos

Si tu aplicación sube archivos (fotografías, reportes u otros) o posee archivos que requieran ser utilizados en todas las aplicaciones, considera centralizar una única fuente de archivos.

Es importante este punto, puesto si tenemos distintos servidores de aplicación, el archivo solo podría permanecer en uno de ellos (donde se subió el mismo). Obvio, esto lo podemos mitigar si guardamos la ruta completa del archivo (y su referencia al servidor) y exponemos los mismos a través de dominios/subdominios específicos, pero no es una solución limpia ni adecuada.

La mejor solución es utilizar servicios como Amazon S3 o Azure Blob Storage que son económicos y no requieren mantenimiento.

También considera el uso de algún CDN, como CloudFront.

#.7. Recuerda monitorear

Recuerda que hay cosas que pueden salir mal y es importante estar preparado. Para ello, debes monitorear los servicios y los consumos (tanto de recurso como de dinero, si usas la Nube).

Aquí tienes distintas alternativas. En el caso de Pixmat, nuestro stack usualmente es utilizar Prometheus y Grafana, pero puedes utilizar servicios como CloudWatch o Azure Monitor.

#.8. ¿Creció tu app o tienes picos de uso? Recuerda la Nube

En IFARHU utilizamos Azure y en Pixmat utilizamos más AWS para ciertas aplicaciones. La gran ventaja de la nube es el escalamiento casi transparente de los recursos según necesidad o disponibilidad.

Otra gran ventaja es que puedes tener distintos ambientes (idénticos) de forma inmediata, lo que te facilitaría el proceso de pruebas o incluso permitiría desplegar ambientes temporales solo para probar características o historias específicas.