Creando aplicaciones con alta disponibilidad en Digital Ocean

Antes de comenzar con este artículo, posiblemente os interese saber un poco más sobre el concepto de [alta disponibilidad en aplicaciones](/aplicacion-alta-disponibilidad) A estas alturas, seguro que os habéis dado cuenta de que Digital Ocean es uno de mis proveedores cloud favoritos, tanto por su precio como por sus características. Por ello, en esta ocasión, voy a mostraros como crear aplicaciones con alta disponibilidad, en Digital Ocean, aprovechando una de sus características más recientes, los load balancers o balanceadores de carga, que nos permítirán escalar horizontalmente nuestras aplicaciones. Si estáis interesados en saber más de este proveedor, aquí os dejo una comparativa entre Digital Ocean y Aws lightsail, donde podréis ver sus características básicas.

Introducción

El objetivo de este artículo será crear la arquitectura cloud necesaria para disponer de un backend que nos ofrezca alta disponibilidad, es decir, que tengamos un servicio que podamos consultar rápidamente y con el menor tiempo de inactividad posible. Nuestra arquitectura de alta disponibilidad se basa en la correcta instalación y configuración de los siguientes componentes: 1. **Backend** 2. **Droplet de Digital Ocean** 3. **Pm2** 4. **Nginx** 5. **Balanceador de carga de Digital Ocean** 6. **Cloud firewall de Digital Ocean**

Backend

Antes de comenzar, lo primero que tenemos que hacer es construir nuestro backend. Para este ejemplo desarrollaremos un servicio en nodejs con dos rutas, una que devolverá un objeto json y otra que nos servirá para comprobar la operatividad del mismo.
app.get('/test', (req, res) => {
  res.json({ text: 'optimized backend' });
});

app.get('/health', (req, res) => {
  res.status(200).end();
});
Sin desarrollar en mayor detalle nuestra implementación (que no es el objetivo de este artículo), construimos un servicio simple en nodejs apoyados en el framework Express. > En una arquitectura final, el método health se encargará de chequear que nuestro servicio esté totalmente operativo, comprobando por ejemplo, que la conexión a la base de datos funcione correctamente. En nuestro ejemplo, simplemente devuelve siempre un status 200.

Droplet

Para hacer funcionar esta aplicación nuestro código deberá ser desplegado en algún tipo de contenedor. En nuestro caso, al usar Digital Ocean, crearemos un droplet "One-click apps" de tipo nodejs, con el que dispondremos de un contenedor con ubuntu y todas las dependencias necesarias para desplegar nuestro backend en nodejs.
Contenedor preparado para aplicaciones nodejs
Para configurar el tamaño del droplet, seleccionaremos la primera opción con dos cpus, más adelante, cuando instalemos pm2, entenderéis por qué. Una vez que creemos nuestro droplet le damos un nombre, por ejemplo, TEST-api y le añadimos una etiqueta a la que también llamaremos "TEST-api". > Las "one click apps" de Digital Ocean son contenedores con toda la configuración necesaria para trabajar con diferentes stacks sin la necesidad de instalar librerías o componentes, como pueden ser nodejs, ruby, mysql o wordpress.

Pm2

Pm2 es un administrador de procesos para aplicaciones nodejs que, entre otras cosas, dotará a nuestra aplicación de las siguientes características: * **Balanceo de carga** : Nos permite escalar nuestra aplicación a través de las diferentes CPUs disponibles. * **Auto-reinicio** : Permite que nuestra aplicación se reinicie si sucede una caída de la misma o de la propia máquina. > Como hemos seleccionado un droplet que poseé dos CPUs, tendremos la posibilidad disponer de dos aplicaciones corriendo en el mismo puerto, pero en diferentes procesos. Para realizar la instalación y configuración de pm2, os dejo mí artículo completo sobre el [ uso de pm2 en aplicaciones nodejs](/uso-pm2-nodejs/)

Nginx

Nginx es un **servidor web de alto rendimiento** que nos permitirá manejar las solicitudes a nuestro backend de una forma eficiente.

Instalación

Para instalar nginx, simplemente ejecutamos la orden
 apt-get install nginx 

Configuración

Ahora tendremos que configurar nginx para que **atienda nuestras peticiones en el puerto 80 y las redirija a nuestro backend**. Para ello, creamos un fichero de configuración de nuestro sitio, usando como base el fichero default de nginx, ejecutando la siguiente orden, donde {site} será el nombre de nuestro sitio:
 cp /etc/nginx/sites-available/default /etc/nginx/sites-available/{site} 
Posteriormente, editamos el fichero y lo dejamos del siguiente modo:
 server {
         listen 80;
         listen [::]:80;
 
         server_name {site};

 
         location / {
                proxy_pass {backend};

        }
}
Aquí, {backend} será la url donde atiende nuestra aplicación, por ejemplo, localhost:3000. Por otra parte, {site}, es el nombre del servidor que podemos dejar por defecto como localhost, o utilizar un dominio, si tenemos alguno apuntando a la ip del droplet.

Crear enlace simbólico

Ahora necesitamos **crear un enlace simbólico a sites-enabled** de nuestro recién creado fichero de configuración de nginx. Esto lo conseguiremos ejecutando la siguiente orden:
 ln -s /etc/nginx/sites-available/{site} /etc/nginx/sites-enabled/
Una vez hecho esto, solo nos queda reiniciar:
 service nginx restart 

Certificado de seguridad

Aunque realmente esto no es algo que vaya a mejorar directamente la disponibilidad del servicio, es importante recordar, que por motivos de seguridad, es **más que recomendable cifrar las peticiones a nuestros servicios**. En nuestro caso, vamos a utilizar un certificado let's encrypt que cubrirá nuestras necesidades de forma gratuita y lo instalaremos de forma automatizada gracias a la herramienta [Certbot](https://certbot.eff.org/).

Instalación

Simplemente ejecutaremos los siguientes comandos:
apt-get update
apt-get install software-properties-common
add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install python-certbot-nginx 
> En la propia página de cerbot podéis seleccionar vuestra configuración (nginx, apache, haproxy), vuestro sistema operativo (ubutu, centos, fedora..) y se os mostrará las instrucciones adaptadas a vuestra selección.

Configuración

Cerbot dispone de una característica que nos proveerá de los certificados y la configuración de nginx de forma automática, con solo ejecutar la siguiente orden:
 certbot --nginx -d {site}  
Con el parámetro -d indicamos el nombre del sitio para el que queremos obtener dicho certificado. Si necesitamos obtener un certificado válido para varios nombres, lo podemos hacer de la siguiente forma:
certbot --nginx -d antoniofernandez.com -d www.antoniofernandez.com
> Es importante que, para que todo funcione correctamente, {site} debe coincidir con el nombre indicado en server_name en la configuración de nuestro nginx.

Auto-renovación

Los paquetes de Cerbot que hemos instalado vienen con un **cron job que renovará automáticamente nuestro certificado de seguridad** antes de que llegue a su fecha de expiración. Podéis comprobar que está funcionando correctamente ejecutando el siguiente comando:
 sudo certbot renew --dry-run 

Load balancer

Los load balancers de Digital Ocean constituyen una potente característica que nos permtirán **balancear la carga de trabajo entre diferentes droplets**, ayudándonos de esta forma, a escalar nuestra aplicación de manera horizontal.

Creación

Para crear un balanceador de carga, simplemente accedemos a networking --> load balancers y "create load balancer". Una vez dentro de la pestaña de configuración, tendremos que seleccionar la región de nuestro balanceador (la misma que nuestros droplets a balancear), así como sus reglas de reenvío y configuración avanzada.
Creación de balanceador de carga en Digital Ocean

Reglas de reenvío

Estas reglas nos permiten definir el comportamiento de nuestro balanceador de carga, estableciendo una **relación entre pares protocolo - puerto** de nuestro balanceador y de nuestros droplets. De esta forma, podemos indicar que, por ejemplo, todas las peticiones https del balanceador sean redirigidas al puerto 443 de nuestro droplet.
Reglas de reenvío en un balanceador de carga

Configuración avanzada

En esta pestaña tenemos la posibilidad de definir ciertas características avanzadas, como son: * **Algoritmo**: Podremos elegir entre round robin o least connections. Por normal general, round robin nos servirá. * **Sticky sessions**: Podremos habilitar o no esta característica, aunque si nuestro tipo de aplicación es sessionless, no lo necesitaremos. * **Health checks**: Apartado muy importante, donde definiremos la url a la que llamaremos para comprobar que nuestro backend funciona. Gracias a que lo hemos configurado previamente en nuestro código, aquí introduciremos el path /health. * **Redirección a SSL** : Redirecciona todo el tráfico http a https. Personalmente, yo siempre lo marco, nunca está de más 😋. > Gracias a los health checks, nuestro balanceador dejará de enviar tráfico a aquellos droplets que no estén respondiendo, balanceando toda la carga hacia aquellos que sí estén funcionando.

Añadir droplets

Una vez que hemos creado y configurado nuestro balanceador de carga, podremos añadir droplets al mismo. En lugar de añadir droplets por nombre, seleccionaremos la etiqueta "TEST-api". > Al añadir nuestros recursos al balanceador mediante una etiqueta, si creamos un nuevo droplet y le asignamos la etiqueta correspondiente, este se agregará automáticamente al balanceador de carga, permitiéndonos escalar horizontalmente de una forma increíblemente sencilla.

Cloud firewalls

Los **cloud firewalls** de Digital Ocean no solo nos ayudan a mejorar la seguridad de nuestra arquitectura, bloqueando ataques de fuentes no deseadas, sino que además, ayudan a mejorar la disponibilidad de nuestra aplicación, ya que este tipo de firewall **bloquea las peticiones antes de que lleguen a nuestras máquinas**. Si queréis saber más, os recomiendo que leáis mi artículo sobre el funcionamiento de los cloud firewalls de Digital Ocean. En este caso crearemos uno, configurando las reglas de entrada para que **solo permita conexiones http y https **. Una vez creado, cuando vayamos a asignarle recursos, seleccionaremos la etiqueta "TEST-api". > Con la asignación de recursos al firewall mediante etiquetas, nos aseguramos que la configuración de la seguridad de nuestros droplets se lleve a cabo de forma automática. Si necesitamos añadir o quitar reglas, con solo modificarlas en el firewall se aplicarán en todos los droplets asignados a nuestra etiqueta. En el caso de que necesitemos añadir más droplets al balanceador, podemos crear uno nuevo a partir de una snapshot del anterior. De esta manera, dispondremos de un droplet, con una configuración exactamente igual al de la snapshot, y con solo aplicarle la etiqueta "TEST-api", le habremos asignado un firewall y añadido a nuestro balanceador de carga, todo esto, de forma automática. Si hemos seguido los pasos correctamente, ya tendremos nuestra aplicación configurada con alta disponibilidad. De todos modos, podéis consultarme vuestras dudas en la sección de comentarios. Si os ha gustado este artículo, compartidlo en vuestras redes 😉