Deploys automáticos usando GIT

Por lo general utilizo git para control de versión, y siempre es útil tener alguna forma de que el deploy al server se haga automáticamente una vez que los cambios son pusheados a master, en lugar de tener que conectarme al server, actualizar repo (git pull) y recién ahi ver los cambios (sobre todo si es más de un server el que hay que deployar).

Hay varias herramientas para lograr esto, desde las más completas de Integración Continua (Jenkins, Travis), hasta otras más específicas (por ejemplo Magallanes, para PHP) pero hoy me voy a enfocar en una solución no tan "empresarial" sino algo más simple, usando solamente git. Es bastante sencillo de setear y la idea es hacer un push desde nuestro entorno de desarrollo y que el contenido impacte en el server.

Configurando el server

Vamos a crear un repositorio bare en nuestro servidor, en mi caso creé una carpeta en /var/repo:

cd /var
mkdir repo
cd repo
mkdir ejemplo.git
cd ejemplo.git
git init --bare

bare quiere decir que el repositorio git no va a tener archivos, sino que va a ser solo de control de versión.

Una vez creado el repo, tenemos que agregar un hook para que los archivos se instalen en el path correcto, en mi caso el directorio de archivos es /var/www/vhosts/ejemplo, por lo que voy a crear el archivo /var/repo/ejemplo.git/hooks/post-receive con el siguiente contenido:

#!/bin/sh
echo "Mensaje de deploy (totalmente opcional :D)"
git --work-tree=/var/www/vhosts/ejemplo --git-dir=/var/repo/ejemplo.git checkout -f

Le damos permiso de ejecución al archivo:

chmod +x post-receive

y con eso terminamos del lado del server.

Configurando el repo local

En nuestro entorno de desarrollo, lo que tenemos que hacer es agregar un remote que apunte al git del server:

git remote add prod ssh://[email protected]/var/repo/ejemplo.git

Una vez agregado el remote, al hacer un push al repo nuestros cambios van a estar disponibles en el server.

git push prod master

Yo por lo general tengo 3 remotes: el del controlador de versión en si mismo (github, gitlab o bitbucket), el de ambiente staging y el de prod. Por lo que una secuencia normal de commits y push sería:

  1. Completar el requerimiento
  2. Commit
  3. Merge a master
  4. Push a origin master
  5. Push a staging master
  6. Test en staging
  7. Fixes (si se encuentran errores en staging, sino ir al paso 12)
  8. Commit de los fixes
  9. Merge a master
  10. Push a origin master
  11. Push a staging master
  12. Push a prod master

Después del paso 12, el código se encuentra en producción.

Últimos retoques

Muchas veces producción tiene más de un server, en cuyo caso lo que tenemos que hacer es editar el archivo .git/config en nuestro repositorio y agregar una url:

[core]
        repositoryformatversion = 0
        fileMode = false
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = [email protected]:Usuario/ejemplo.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
[user]
        email = [email protected]
[remote "prod"]
        url = [email protected]:/var/repo/ejemplo.git
        url = [email protected]:/var/repo/ejemplo.git

De esta forma, al hacer git push prod master, el push se hace a server1 y server2 (y como ambos servers tienen el hook que seteamos arriba, inmediatamente los archivos quedan disponibles).