`

Blue/Green deployment con Docker, docker-compose y NGINX

Buenas!

En este post vamos a tratar como hacer un deployment de una manera bastante rústica en donde vamos a tener 0 downtime del servidor, y le digo rústica porque no tenemos una integración continua ni un script que nos haga todo por nosotros.

Uno de los problemas principales que tuve en Cafecito fue que a la hora que empezó a crecer el trafico, ya no podía hacer deploys y que esté 2 segundos abajo la app, los deploys tenían que ser transparentes para la arquitectura que tengo, y acá es cuando aparecen los deployments blue/green.

Antes de empezar y como ya saben, todo el contenido es 100% gratuito, con lo único que me ayudarían es dándome un follow en Twitter: @DamianCatanzaro  y compartiendo el contenido para que más gente lo pueda usar 😁. Si les gusta mucho el contenido pueden apoyarme con un Cafecito ☕️!

Primero vamos a ir a la teoría y después como es aplicado.

La arquitectura más simple que solemos tener es un container de Docker donde tenemos nuestra app apuntando a un puerto, pongámosle puerto 3000 para ejemplificar la idea, y nuestro NGINX rutea ese puerto gracias a un proxy-reverse.

Cuando hacemos el build del nuevo container, vamos a tener 2 o 3 segundos de downtime ya que nuestra app se tiene que ejecutar de nuevo y si entra gente en esos 3 segundos van a ver un error 502 en la página.

Para solucionar esto, podemos hacer un build de nuestro mismo container pero en vez de que apunte al puerto 3000, que apunte al 3001, esperamos que buildee y se ejecute correctamente y ahí hacemos el cambio en el NGINX, apuntamos nuestro proxy-reverse al puerto 3001, lo recargamos y todas las nuevas personas que entren van a caer en la nueva aplicación, sin ningún tipo de inconveniente.

Ahora que ya tenemos la teoría vamos a ir a la practica, como hacemos esto con Docker, docker-compose y NGINX?

Vamos a crear 2 docker-compose, uno que sea el "blue" este va a apuntar al puerto 3000, y otro que sea el "green", este va a apuntar al puerto 3001.

docker-compose.blue.yml

version: "3"

services:
    app-blue:
        container_name: app-blue
        image: app-blue
        restart: always
        build: .
        environment:
            NODE_ENV: production
        ports:
            - 3000:3000

docker-compose.green.yml

version: "3"

services:
    app-green:
        container_name: app-green
        image: app-green
        restart: always
        build: .
        environment:
            NODE_ENV: production
        ports:
            - 3001:3000

Y en nuestra config del NGINX vamos a tener algo parecido a esto (ya lo tenemos apuntado al puerto 3000).

server {
    listen 443 ssl http2;

    server_name tuapp.com;

    location / {
        proxy_set_header  Host $host;
        proxy_set_header  X-Real-IP $remote_addr;
        proxy_set_header  X-Forwarded-Proto https;
        proxy_set_header  X-Forwarded-For $remote_addr;
        proxy_set_header  X-Forwarded-Host $remote_addr;
        proxy_pass http://localhost:3000;
    }
}

Con todo ya configurado lo que nos queda hacer es el build de nuestro docker-compose y levantarlo, vamos a empezar por el blue ya que como declaramos más arriba, es el que apunta al puerto 3000.

docker-compose -f docker-compose.blue.yml up -d --build

Si corremos un "docker ps" lo vamos a ver levantado y apuntando al puerto 3000

Esto es lo que hacemos normalmente a la hora de levantar nuestra app, ahora entra la parte interesante, hacemos un cambio, necesitamos deployar de nuevo pero a la hora de hacer el build, no la hacemos en el blue, la vamos a hacer en el green.

docker-compose -f docker-compose.green.yml up -d --build

Esto nos va a levantar nuestra misma app, pero en el puerto 3001, así que vamos a ir a nuestro archivo de configuración en el nginx y cambiar la linea donde apunta al puerto 3000 al 3001.

proxy_pass http://localhost:3001;

Y le hacemos un reload.

sudo nginx -s reload

En cuanto tiremos este comando, todos nuestros nuevos usuarios que entren a la página o llamen a nuestro servicio van a caer en el nuevo build y resta matar al viejo, para que no consuma procesamiento y espacio (el viejo es el blue).

docker-compose -f docker-compose.blue.yml down

En cuanto queramos hacer otro deploy hacemos lo mismo pero en este caso hacemos un build del blue (que es el que no está arriba), cambiamos el puerto al 3000, recargamos el servidor y matamos el green.

Como dije arriba, esto es recontra manual y se puede automatizar con un script, pero para proyectos chicos o si no quieren tener que estar armando una infraestructura gigante y compleja funciona muy bien.

Espero que les sirva, cualquier cosa me pueden contactar por Twitter: @DamianCatanzaro o comentar acá abajo!

Invitame un café en cafecito.app

Saludos!

Follow @DamianCatanzaro