Scripts y técnicas de despliegue continuo para una web con Git

2020-11-16 - Categorías: General / Magento / PHP / Symfony / WordPress

Automatizar la publicación de nuevas versiones es una técnica de desarrollo de aplicaciones que se denomina Despliegue Continuo o Continuous Deployment en inglés (CD). Se suele usar junto con el Continuous Integration (CI), en el que se elabora una serie de pruebas automáticas sobre el software.

Tener esto automatizado nos ahorra mucho tiempo, nos dará velocidad en todos estos pasos intermedios ya que no tendremos que repetirlos continuamente, y podremos centrarnos en desarrollar para cada iteración.

Durante las pruebas puede notificarnos en caso de errores, realizar todo tipo de chequeos, o elaborar documentación sobre el proyecto para el resto del equipo. Pero una vez que tenemos el primer paso montado del CI, es interesante seguir con el segundo paso del CD. A continuación comparto unos scripts e instrucciones para una web en WordPress, Symfony o Magento 2, con GitHub o BitBucket. Así es como funciona también aquí en JnjSite.com..

Un poco de teoría, ideas generales

En teoría, tenemos que trabajar las siguientes funcionalidades para el desarrollo de aplicaciones web:

  • Desarrollar en nuestro entorno de desarrollo, trabajando sobre ramas de desarrollo diferenciadas, compartiendo y fusionando.
  • Lanzar pruebas de integración continuas sobre el software con cada actualización de desarrollo que se comparta entre los desarrolladores, o incluso individualmente en nuestro entorno.
  • Las pruebas de integración pueden lanzar informes de errores, generar documentación, y desembocar en nuevos eventos lanzando acciones como la propagación de los cambios entre las fases: desarrollo, staging, producción.. Estas fases suelen cambiar dependiendo del proyecto.
  • El despliegue continuo puede darse en todos los entornos, dependiendo del proyecto. Y en teoría tiene que ser automático según unas condiciones. Puede ser de la rama develop a un entorno con cada push, de la rama staging una vez al día, quizá de la rama master de producción en cada noche, etc..

Un par de estrategias de desarrollo

Por ejemplo si seguimos un flujo de trabajo parecido al de Git Flow, producción podría estar en la rama master, desarrollo en develop, cada nueva iteración o funcionalidad se desarrollaría en su propia rama, etcétera..

Otra forma podría simplemente ser lanzar las pruebas de integración en la rama develop, sin despliegue. Y publicar en producción cada vez que se actualiza la rama master.

Preparar las tareas de despliegue

Normalmente existe un repositorio central de Git en donde se van guardando las actualizaciones. Y en el servidor debería existir un clonado del repositorio central. Para el entorno de producción podría estar montado de la siguiente forma, haciendo esto desde línea de comandos para clonar con Git:

git --work-tree=./public_html/ clone git@servidor-de-repos.com:ruta/al/repo.git directorio_local_del_repo

Para lanzar el despliegue puede servir un script como el siguiente en Shell Script, que estaría en el servidor, en su carpeta local del proyecto. Esto serviría para webs WordPress:

#!/bin/bash
cd /home/usuario_proyecto/directorio_local_del_repo
git checkout master
git fetch --all
git reset --hard origin/master
git pull
echo Updated with the latest!
sleep 1
rm -rf /home/usuario_proyecto/public_html/wp-content/cache/*
touch /home/usuario_proyecto/public_html/wp-content/cache/index.html
echo Finished!

Este script está guardado en un fichero deploy.sh con sus permisos de ejecución. Se puede lanzar desde línea de comandos manualmente. Simplemente hace un pull de la rama master, porque se supone que lo que hay en la rama master está bien para publicar en producción.

Para el caso de una web con Symfony podría servir un script como el siguiente:

#!/bin/bash
cd /home/usuario_proyecto/directorio_local_del_repo
git checkout master
git fetch --all
git reset --hard origin/master
git pull
echo Updated with the latest!
sleep 1
rm -rf /home/usuario_proyecto/public_html/var/cache/prod/*
rm -rf /home/usuario_proyecto/public_html/var/log/*
echo Finished!

Es parecido al de WordPress, sólo que ahora tiene unas tareas de limpieza de logs y caché en distintos directorios. Para el caso de un Magento 2 la tarea de despliegue es algo más complicada, pero la idea es la misma:

#!/bin/bash
cd /home/usuario_proyecto/public_html/
php bin/magento maintenance:enable

cd /home/usuario_proyecto/directorio_local_del_repo
git checkout master
git fetch --all
git reset --hard origin/master
git pull
echo Updated with the latest!
sleep 1

cd /home/usuario_proyecto/public_html/
php bin/magento cache:clean
php bin/magento setup:upgrade
php bin/magento cache:flush
php bin/magento setup:static-content:deploy -f
php bin/magento setup:di:compile
php bin/magento indexer:reindex
php bin/magento cache:enable

rm -rf var/cache/*
rm -rf var/generation/*

#sudo service redis restart
#sudo service php7.2-fpm restart
#sudo service apache2 restart

php bin/magento maintenance:disable
echo Finished!

Lanzar las tareas de despliegue

Entonces, una vez tenemos estos scripts funcionando. Lo más sencillo sería lanzarlos con una tarea programada a ciertas horas del día. Este sería el caso si quisiéramos programar ciertos despliegues, por ejemplo, para las noches a las 3 de la madrugada.

Otra forma es lanzar estos scripts cuando hacemos push al repositorio Git. Si estamos en Bitbucket, GitHub, GitLab, etc.. siempre tenemos eventos que pueden disparar acciones. Se suelen llamar Webhooks, dentro de Git también se pueden configurar lo que se llaman Hooks y tener así tantos scripts con las acciones que necesitemos sin disponer de paneles de control como Cpanel, Plesk, etc.

Vamos al grano, por ejemplo en GitHub se pueden lanzar peticiones al servidor de despliegue en esta sección:

En Bitbucket hay otra sección parecida, desde donde se puede hacer lo mismo. Lanzar peticiones web a otro servidor cuando hay un push:

En el servidor de destino se podría tener una herramienta del tipo Jenkins. Pero te propongo simplificarlo con otro sencillo script en el servidor de destino. Por ejemplo, se podría poner un fichero llamado:

https://jnjsite.com/8aa97d90fecf42d0dd69d7c84edbb9cd.php

Y dentro de este fichero PHP en el servidor, hacer el despliegue lanzando el script en Shell Script anterior que quisiéramos. El codigo fuente podría ser como el siguiente:

<!DOCTYPE html>
<html>
<body>
<pre>
<?php
$ret = shell_exec('/home/usuario_proyecto/deploy.sh');
echo $ret;
?>
</pre> 
</body>
</html>

Esto es todo, si todo está bien configurado, con cada push a Git se lanzaría un Webhook, que simplemente hace una consulta al servidor que queramos en la URL que queramos, y en dicha URL hay un Script en PHP que lanza las tareas de despliegue que queramos en Shell Script.

Un ejemplo de respuesta que daría la URL podría ser como el siguiente:

Your branch is up to date with 'origin/master'.
Fetching origin
HEAD is now at c866d040 Merge latest updates.
Already up to date.
Updated with the latest!
Finished!

Más información sobre CI/CD de posts anteriores

Hay unos posts anteriores aquí que quizá te interesan sobre despliegues y pruebas de integración:

Ya a partir de aquí es suma y sigue con las tareas que necesites. Si has llegado hasta aquí espero haberte servido de ayuda. Si no no dudes en dejar un comentario 👍

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

 

© 2020 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.