Historia

Hace unas semanas este blog se vió afectado por el incendio en los servidores de ovh que dejó el sitio web caído por unos días.

Afortunadamente toda la web se encuentra en un repositorio en github y no perdí nada importante. Me da pena haber perdido un fichero con 2G de usuarios y contraseñas que había capturado con un ssh-honeypot.

Cuando empecé este blog no había nada automatizado. No había certificados ssl, el servidor web estaba instalado en el sistema y copiaba por scp el html compilado en mi máquina. Por suerte, había avanzado en la automatización del despliegue de esta web para ser más independiente del proveedor de vps de turno.

Objetivo

El objetivo es desplegar en el servidor los cambios que hagamos en local, con solo hacer solo git push al repositorio del vps.

Introducción

Este blog es un sitio web estático generado por jekyll. Sin entrar en particularidades de jekyll, la manera de generar esta blog consiste en escribir los posts en markdown y compilar para generar los ficheros html.

Infraestructura

Toda la infraestructura, el servidor web y el sistema de comentarios, está dockerizado. Puedo versionar mi infraestructura con git, ampliarla y modificarla sin tener que instalar a mano cada software en el vps. Esto permite que la web sea autocontenida, todo lo que necesito está en un repositorio.

Con docker-compose levanto todos los contenedores de un solo comando.

Git Hooks

Git ofrece una manera de lanzar scripts cada vez que ocurren eventos en el repositorio. En el argot de git se le conoce como git hooks.

Se pueden disparar scripts tanto en eventos del cliente (commit, merge) como en el lado del servidor (pre-receive, post-receive).

Configuración servidor

Tenemos que crear un repositorio de git bare

mkdir hardfloat-blog.git
cd hardfloat-blog.git
git init --bare

Creamos el hook que se va a ejecutar en el servidor después de recibir cada push.

vim hooks/post-receive

Con el seguiente contenido:

#!/bin/bash

GIT_DIR=/home/debian/hardfloat-blog.git
GIT_WORK_TREE=/home/debian/hardfloat-blog 

if [ ! -d $GIT_WORK_TREE ]; then
        mkdir $GIT_WORK_TREE
fi

git --git-dir=$GIT_DIR --work-tree=$GIT_WORK_TREE checkout -f master
cd $GIT_WORK_TREE
git --git-dir=$GIT_DIR --work-tree=$GIT_WORK_TREE submodule update --init --recursive
docker-compose -f docker-compose-prod.yml down &&
docker-compose -f docker-compose-prod.yml up -d

Y damos los permisos de ejecución al script:

chmod +x hooks/post-receive

Con el repositorio clonado, docker-compose se encargará de construir los contenedores y levantar los contenedores de forma automática.

Configuración cliente

Esto es lo más fácil, tan solo tenemos que agregar un remoto a git desde el que hacer push.

La plantilla es la siguiente:

git remote add prod ssh://[username]@host:[port]/home/andres/hardfloat-blog.git

Ahora solo tenemos que hacer un git push a producción y el hook se encargará de reiniciar todos los contenedores y generar los ficheros html al momento

git push origin prod

Conclusiones

Aún me quedan cosas por automatizar como la generación y renovación de los certificados y algunos permisos en directorios a la hora de levantar los contenedores. El tema de los certificados se puede automatizar desde el sistema con certbot, aunque también me gustaría hacerlo en docker.

Los hooks de git son un buen punto de entrada para realizar tareas en cada push. Por ejemplo, podríamos enviarnos un mail cuando se desplieguen los cambios, desplegar solo si pasan todos los test, en caso contrario descartamos el despliegue.

Desplegar con un solo comando es una auténtica gozada. Elimina la fricción de sentarse a escribir y enviar los cambios al servidor.