Desplegando Aplicaciones Web con Git

Utilizando git hooks para mejorar nuestro workflow.

Escrito por Matías Navarro Carter hace 4 semanas
En: Tooling / Git
Lectura de 8 minuto(s).

Si hay algo que me ha hecho progresar en mi corta carrera como desarrollador web ha sido una sola gran cosa: ser flojo.

Siempre estoy buscando formas más eficientes de hacer las cosas, y por eficiencia tomo mi propia definición: hacer algo con menos esfuerzo, en menos tiempo, y con el mismo resultado.

Una de aquellas cosas era pasar mi código a producción. Probé FTP, Bitbucket Pipelines y un montón de otras soluciones. FTP es lento e inseguro. Bitbucket pipelines es lento, poco controlable y pronto pasaría a ser de pago. Tenía que buscar otra opción.

Pensé en la API que me gustaría tener. Me pregunté: “¿En un mundo ideal, cómo me gustaría pasar mi código a producción?” La respuesta era obvia: escribiendo un comando en el directorio raíz de mi proyecto.

Comencé a investigar y fue allí cando descubrí que Git podía ayudarme, específicamente dos de sus más potentes features: repositorios remotos y hooks.

El Procedimiento

Los Requisitos

Lo primero que necesitas es tu propia VPS. No importa si tienes Apache, Ngnix u otro servidor web. Pero lo que si es indispensable, es que debes tener instalado git. Si utilizas un derivativo de Debian, como Ubuntu, lo más probable es que tu VPS ya venga con git. En caso de que no, puedes instalarlo utilizando sudo apt install git. Si vives en Chile, puedes conseguir una VPS a un precio decente en OpenCloud. Si no, DigitalOcean sirve también.

Además, se da por sentado que tienes un dominio configurado para funcionar con tu máquina de producción, y su correspondiente VirtualHost (si usas Apache). Si no, entonces no podrías probar que http://tu-sitio-de-produccion.cl funciona.

Recomendación: Siempre debes configurar el acceso a tu máquina VPS a través de una Clave SSH, al menos para la cuenta root. No es obligatorio, pero es mucho mejor, porque cuando quieras desplegar tu código a producción, se hará automáticamente sin preguntar por contraseña.

Configurando la VPS

Lo primero que debes hacer es entrar a tu VPS. Luego, ejecuta lo siguiente:

mkdir /var/repos && cd /var/repos

Esto creará una carpeta repos en el directorio var, e ingresará a ella. Una vez dentro de tu carpeta, repite el procedimiento anterior, esta vez creando la carpeta para tu nuevo repositorio:

mkdir [nombre-de-tu-repo].git && cd [nombre-de-tu-repo].git

Una vez dentro de esta carpeta (que tendrá el nombre de tu repo), debes iniciar un nuevo repositorio git, pero con un flag especial (si tu VPS no tiene git, un simple apt install git soluciona todo).

git init --bare

Lo que hace este comando es crear un repositorio bare, es decir, un repositorio git hecho sólo para recibir pushes, pero no para mantener un working tree.

Luego de esto, entramos a la carpeta hooks:

cd hooks

Alli creamos un archivo llamado post-receive.

nano post-receive

Debemos colocar lo siguiente en el archivo:

#!/bin/sh
git --work-tree=[ubicacion/de/tus/archivos/html/para/servir] --git-dir=/var/repos/[tu-repo].git checkout -f

Lo que hacen estas líneas es que van a forzar un comando git checkout. Wait ¿Git checkout en un repositorio que no tiene working tree? ¿Qué clase de magia negra es esta? En realidad, aquí está el meollo del asunto. Engañaremos a git y le diremos que haga un checkout en otro lugar, construyendo así nuestros archivos en esa ubicación, específicamente, en la ubicación donde vas a servir tus archivos para la web. Bien podría ser /var/www o /home/[usuario]/public_html/. No debes olvidar añadir el directorio del repositorio al final.

Guardamos y no olvidamos hacer ejecutable el archivo:

chmod +x post-receive

Todo lo que acabamos de hacer no es más que lo que se conoce como un git hook. Los hooks son acciones que puedes ejecutar luego de cierto hito. El hook de post-receive se ejecuta cuando el repositorio recibe un push. Entonces, cada vez que hagas un push a ese repositorio, el working tree en tu directorio para ser servido en la web, se actualizará también. ¡Ah! ¡Cuánto me gusta el software bien diseñado!

Configurando tu Máquina

Ahora que tenemos nuestro repositorio en nuestra VPS, ya podemos comenzar a mandarle pushs. Para ello, simplemente añade el nuevo repositorio que hiciste como un remote al repositorio actual:

git remote add [nombre] ssh://[usuario-vps]@[ip-o-fdqn-vps]/var/repos/[tu-repo].git

Es muy importante que definas el nombre de tu remote. Una buena convención es testing o production, dependiendo del caso. Además, debes incluir las credenciales ssh de tu VPS (el usuario y la dirección de la misma) y luego la ruta al repositorio bare.

Nota: Si el puerto SSH de tu VPS es distinto al 22, incluye el puerto luego de la IP o FDQN del mismo, antecediéndole :. Al final, deberías tener algo como esto: git remote add production ssh://root@server.com:22222/var/repos/web.git.

Luego, desde tu consola, cada vez que cambies el código y comitees los cambios, debes hacer lo siguiente:

git push [nombre-remote] master

Con esto le decimos a git que haga un push al repositorio remoto (usando el nombre) de la rama master (que se supone contiene los últimos cambios de tu código).

Requisitos extra

Si utilizas un framework o algún package manager como composer, o si has exlcuido ciertos archivos utilizando un gitignore, quizás tengas que hacer un par de tweaks más.

Por ejemplo, utilizo mucho PHP y composer, lo que significa que en mi VPS, debo ir a la carpeta donde tengo los archivos para servir a la web, y realizar un composer install luego del primer push. Si agrego alguna dependencia, debo hacer un composer update en el futuro.

Además, posiblemente en frameworks como Laravel, Symfony, o Codeigniter, debas ajustar algunos permisos de carpetas para que sean leidos por tu servidor.

Sin embargo, estas tareas se pueden realizar de forma automática también. Lo puedes incluso añadir a tu post-receive. Sería algo como esto:

#!/bin/sh
git --work-tree=[ubicacion/de/tus/archivos/html/para/servir] --git-dir=/var/repos/[tu-repo].git checkout -f \
&& chown [usuario-web-server]:[grupo-web-server] -R [ubicacion/de/tus/archivos/html/para/servir] \
&& rm [ubicacion/de/tus/archivos/html/para/servir]/web/app_dev.php # Para aplicaciones Symfony

Posibles Mejoras

Si eres realmente flojo, lo que puedes hacer es un script de bash que automatice todo el proceso: que haga el virtualhost, que cree el repositorio y que añada el remote. Este script tendría un solo argumento: el nombre de dominio del virtualhost. Ese nombre se pasaría al repositorio y al remote.

Las Ventajas

Te preguntarás, “¿Para que realizar toda esta complejidad?” Quizás suena complejo al principio, pero luego de hacerlo dos o tres veces ya no lo es. Ahora lo utilizo para cada proyecto que hago, y no dejaré de utilizarlo nunca más, por varias razones:

Tú tienes el control

Puedes actualizar tu ambiente de desarrollo automáticamente, cuando tu quieras. Lo que yo suelo hacer es un script llamado “deploy.sh” que testea mi código con pruebas unitarias y luego hace un push si pasa. También puedes usar git hooks en tu repositorio y hacer lo mismo en un pre-commit hook.

Es Seguro

He visto desarolladores que utilizan FTP para hacer este tipo de cosas. La verdad es que FTP es lento e inseguro. SSH es un procotolo extremadamente rápido y muchísimo más seguro. Te sorprenderás lo rápido que pasará tu código a producción.

Es rápido

Sólo debes hacer un simple git push y ya estás en producción. ¿Qué más rápido que eso? Además, cuentas con los beneficios de Git, que jamás escribe un archivo dos veces, por lo que cada vez que cambias algo sólo se suben los objetos que cambiaste.

Hazme saber qué te parece y qué técnicas utilizas para pasar tu código a producción.