Cómo desplegar a producción sin tiempo de caída

Cómo desplegar a producción

Hay una serie de puntos que conviene tener en cuenta a la hora de planificar un proceso de despliegue sin tiempo de caída. En este post queremos compartir contigo nuestra experiencia a la hora de implementar un despliegue de este tipo para la API de Connectif, que recibe tráfico externo, tiene dependencia de la base de datos y consta de servicios dependientes como el frontend.

Una de las ventajas del escalado horizontal (por cierto, en este post te contamos nuestra historia con el escalado horizontal 😉) es la posibilidad de desplegar sin tiempo de caída. Es decir…

 

Lograr que el servicio esté siempre disponible para el usuario durante el despliegue de la aplicación.

 

No todos los servicios tienen la misma necesidad de un despliegue sin tiempo de caída pero, en cualquier caso, es necesario conocer qué aspectos hay que tener en cuenta para planificar un proceso de deployment de este tipo.

 

En Connectif disponemos de varios servicios cuyas necesidades para un despliegue sin tiempo de caída varían de uno a otro. En este artículo nos centraremos en el caso más complejo, la API de Connectif (Connectif API).

Lo primero de todo a la hora de implementar un proceso de escalado sin tiempo de caída es trabajar con una plataforma que permita escalar horizontalmente.

 

En Connectif usamos Kubernetes, una plataforma extensible y de código abierto que nos provee de una forma sencilla y rápida de escalar horizontalmente Connectif API y el resto de servicios que forman parte del ecosistema de Connectif (Connectif Front, Email sender, Push sender, Sms sender, etc..). 

 

En sistemas complejos de microservicios como el nuestro, Kubernetes proporciona una capa de abstracción sin la cual algunos procesos podrían volverse muy complicados. 

Entre los procesos que simplifican de forma considerable esta plataforma se encuentra el despliegue de aplicaciones con zero downtime. 

Qué tener en cuenta para planificar un deployment sin tiempo de caída

Estos son, para nuestro equipo, los principales puntos que hay que tomar en consideración:

 

  • Balanceo de carga: mientras la aplicación está desplegando debemos redireccionar el tráfico de entrada  en función de si la instancia de la aplicación está lista (ready),en proceso de despliegue o finalizada. 

  • Estrategia de despliegue: Cuando queramos lanzar un despliegue, deberemos levantar una nueva instancia de la aplicación que convivirá con la instancia anterior mientras se despliega. Una vez esté lista, empezará a recibir tráfico desde el balanceador mientras la instancia con la versión antigua deja de recibirlo. Finalmente eliminaremos la instancia que contiene la versión antigua..

  • Parada controlada: el servicio debe ser capaz de parar de forma controlada, sin comprometer la consistencia de los datos que maneja.

  • Migraciones de base de datos: la compatibilidad de dos versiones distintas de la aplicación con un esquema de base de datos es una consideración a tener en cuenta para un despliegue sin tiempo de caída.

 

Retro compatibilidad: Los servicios que dependen del servicio que estamos desplegando deben ser compatibles con dos versiones simultáneamente.

Balanceo de carga, Nginx Ingress

En Connectif disponemos de varios servicios que deben ser accedidos desde el exterior: Front, API, Public API, etc. Ya que estos servicios tienen configuración de alta disponibilidad, necesitan de un balanceador de carga como punto de entrada común.

 

En nuestro caso, usamos Ingress, que se ha convertido en el estándar de facto en Kubernetes. 

 

Sin tener que configurar nada más allá del usual servicio para las aplicaciones en alta disponibilidad, Ingress nos permite redireccionar el tráfico de un nodo que está siendo reemplazado a otro que aún sigue activo (con la versión anterior del programa). Una vez la nueva versión ha sido desplegada en el nuevo nodo, el tráfico empieza a enrutarse a éste.

Creación de pods y cambio de enrutamiento entre pods.

Estrategia de despliegue

Kubernetes provee de varias estrategias para el despliegue de contenedores. En nuestro caso, la que usamos es la RollingUpdate strategy, que es, además, la estrategia de despliegue por defecto. Es decir, nos facilita la vida porque no tenemos que cambiar nada en nuestra plantilla de deployment.

 

Sin embargo, para asegurar que siempre una réplica estará activa, en Connectif lo que hacemos es configurar un Pod Dirupcion Budget, un objeto de Kubernetes que se asocia a un deployment del mismo nombre y que se despliega en nuestro namespace.

 

apiVersion: policy/v1beta1

kind: PodDisruptionBudget

metadata:

  name: connectif-app

  namespace: connectif

spec:

  minAvailable: 1

Ejemplo de Pod Disruption Budget

 

Parada controlada

En Connectif API nombramos este proceso como “Graceful Shutdown”. 

 

De lo que se trata es de que, en el momento en el que el servicio recibe la señal de parada (SIGTERM), se inicia un proceso de parada de todas las conexiones (conexiones entrantes, colas, base de datos, monitoring, etc.). 

 

Por lo que respecta al despliegue con zero downtime debemos asegurar que el tiempo configurado en Kubernetes para la parada del pod (por defecto 30 segundos) es suficiente para que se complete totalmente. El valor viene indicado por el parámetro terminationGracePeriodSeconds que, en nuestro caso, hemos establecido a 90 segundos, lo cual nos permite finalizar las conexiones abiertas con Keep-alive.

Migraciones de base de datos

El despliegue de Connectif depende de una base de datos cuyo esquema suele sufrir cambios. ¿Cuándo aplicar estos cambios a la base de datos? El momento exacto depende de la filosofía que se adopte. En nuestro caso implementamos una estrategia “database first”, lo que significa que ejecutamos las tareas de actualización justo antes del despliegue de la nueva versión de la aplicación. El proceso es el siguiente: 

 

  1. Lanzamos las migraciones en un Job de Kubernetes, que está monitorizado por un contenedor que se ejecuta en el mismo pod que Connectif API (la configuración es algo compleja, puedes encontrar un buen artículo al respecto aquí). 

  2. Cuando la migración concluye, el pod termina de arrancar y es en este punto donde la nueva versión empieza a convivir con la antigua versión, que debe a su vez ser compatible con los cambios de base de datos introducidos en la migración.

 

Es importante detenerse en analizar este proceso ya que implica, a su vez, que los cambios en la base de datos deban realizarse de forma más atómica. 

 

La duda que surge es: ¿Si la migración se ejecuta pero la nueva versión no despliega es un problema? 

Si un cambio en la base de datos rompe la compatibilidad hacia atrás, debemos dividir el despliegue en varios para evitarlo, de forma que la aplicación en su versión previa sea siempre compatible con el estado de la base de datos tras aplicar la migración.

Retro-compatibilidad

Uno de los principales problemas que aparecen cuando se implementa una estrategia de zero downtime es asegurar la compatibilidad de versiones. 

 

Los servicios que dependen de este despliegue deben ser compatibles con la versión anterior y la versión desplegada. 

 

En nuestro caso esa dependencia se traduce en el front de Connectif (que se ejecuta en un contenedor independiente). De igual forma en la que aseguramos que las migraciones no rompen la compatibilidad entre distintas versiones, aquí debemos asegurarnos de que Connectif Front es compatible con la nueva versión de la API. Si esto no se cumple, debemos dividir el despliegue en cambios más atómicos para que así sea.

Si vas a realizar un despliegue sin tiempo de caída...

En este artículo hemos tratado de cubrir los puntos que nos han ayudado a implementar un despliegue con tiempo de caída cero para Connectif API. Sin embargo, conseguir un despliegue de este tipo puede variar bastante de una aplicación a otra, por lo que recuerda que deberás tratar de descubrir cuáles son las relaciones, puntos de entrada y procesos de inicialización y cierre de la aplicación para analizar los cambios y la infraestructura necesarios. 

 

Con respecto a Kubernetes, podemos decirte que, para nosotros, se ha revelado como un gran aliado, dado que los procesos que implementa están estandarizados y la ayuda disponible de la comunidad es abundante.

 

Esperamos que este artículo y nuestra experiencia particular con la API de Connectif pueda ayudarte. En el blog tienes otros posts que cuentan cómo hemos hecho frente a diversos retos técnicos a lo largo del tiempo. Estaremos encantados si pueden serte de utilidad. 

¿Quieres hablar con uno de nuestros especialistas?

Te ayudaremos a encontrar el plan ideal que necesitas para disfrutar de las todas las ventajas que ofrece el marketing automation.

¡Déjanos tu número y te llamaremos sin compromiso!

Lo último de Connectif