Pues hoy tocaba Drupal 8 🙂 y he estado buscando la mejor forma, tanto de despliegue en App Service como de automatización con Azure DevOps, para montar este escenario. No soy ninguna experta en Drupal, por lo que si hay algún punto que se pueda hacer mejor el feedback siempre es bien recibido. En este artículo te cuento cómo montar un entorno en local que luego migraré a Microsoft Azure.
Entorno en local con ddev
Existen diferentes formas de crear tu entorno para Drupal en local, pero el más sencillo con el que me he encontrado ha sido con la herramienta ddev. He seguido las instrucciones de la documentación oficial de Drupal. Por lo que básicamente he hecho lo siguiente:
He instalado ddev, que me ayuda a montarme un entorno de desarrollo de forma rápida, apoyándose en Docker:
curl -L https://raw.githubusercontent.com/drud/ddev/master/scripts/install_ddev.sh | bashDespués he creado un sitio con Drupal 8 con la ayuda de Composer.
# Replace my_site_name!
export SITE_NAME=drupal-src
composer create-project drupal-composer/drupal-project:8.x-dev --stability dev --no-interaction $SITE_NAME
cd $SITE_NAMEDentro de mi proyecto he configurado ddev:
ddev config --docroot web --projectname $SITE_NAME --projecttype drupal8y lo he arrancado para que me genere los contenedores pertinentes y me de la URL por la que acceder a mi nuevo sitio:
ddev startPara darle un poco de emoción al asunto, he elegido la plantilla de demo durante el asistente.

Exportación de la base de datos a Azure Database for MySQL
Ahora que todo funciona correctamente en local, lo siguiente que he hecho ha sido crearme una base de datos en Azure Database for MySQL. La versión de MySQL que he desplegado es la 5.7 , ya que la versión 8 parece que todavía no anda muy bien con Drupal 8.
Ahora lo que necesito es hacer un backup de la base de datos asociada a mi entorno de desarrollo a través del siguiente comando con ddev:
ddev export-db --gzip=false >/tmp/db.sqlComo todavía no tengo una base de datos en Azure a la que volcar esta información, solo un servidor de base de datos, a través del cliente de MySQL me he conectado al servidor que acabo de crear y me he creado una base de datos vacía:
mysql -h YOUR_SERVER.mysql.database.azure.com -u USER@YOUR_SERVER -p YOUR_PASSWORD
CREATE DATABASE drupaldb;Nota: si tienes instalado MySQL Workbench puedes usar el cliente de MySQL exportando la siguiente ruta:
export PATH=$PATH:/Applications/MySQLWorkbench.app/Contents/MacOSPor último he volcado el backup en la nueva base de datos:
mysql -h YOUR_SERVER.mysql.database.azure.com -u USER@YOUR_SERVER -p YOUR_PASSWORD drupaldb < /tmp/db.sql Asegurate de que has permitido en tu servidor de MySQL en Azure la conexión desde otros servicios de la nube (y tu IP por si quieres probar en local). También he deshabilitado el SSL para este artículo.
Ahora debes añadir la configuración de la base de datos a web/sites/default/settings.php (recuerda que hay mejores formas de hacer esto. Esto es solo un piloto):
$databases['default']['default'] = [
'database' => 'drupaldb',
'username' => 'USER@YOUR_SERVER',
'password' => 'YOUR_PASSWORD',
'host' => 'YOUR_SERVER.mysql.database.azure.com',
'port' => '3306',
'driver' => 'mysql',
'prefix' => '',
'collation' => 'utf8mb4_general_ci',
];También necesitas añadir un hash_salt a este archivo:
$settings['hash_salt'] = 'CHANGE_THIS';Para evitar problemas a la hora de migrar al nuevo entorno he deshabilitado el preprocesamiento de los archivos javascript y css:
/**
* Disable CSS and JS aggregation.
* https://stackoverflow.com/questions/57027471/javascript-css-not-loading-after-drupal-8-migration
*/
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;Lo ideal es habilitarlo de nuevo una vez que haya finalizado el despliegue.
He eliminado el archivo .gitignore del proyecto para que todos los cambios que realice en local vayan a mi nueva imagen. Obviamente habrá que afinar el mismo para que solo se suban los directorios y archivos que corresponda.
DockerFile
Para poder desplegar mi solución en un contenedor en App Service necesito un archivo Dockerfile. El equipo de App Service tiene diferentes imágenes subidas en Docker Hub, con el código de las mismas en GitHub, por lo que voy a utilizar esta como base. La estructura de mi proyecto quedaría de esta forma, estando en drupal-src mi proyecto:

Hay algunos ficheros que no necesitas, como drupal-database-install-tasks.php o incluso parte del script de entrypoint.sh, donde inicialmente recupera el código fuente de la aplicación de un repositorio git. Por otro lado he hecho los siguientes cambios:
Docker file
En este archivo solo he añadido la sentencia ADD . /drupal-src ${DRUPAL_PRJ} para que todo el contenido de mi código fuente se copie dentro de la imagen.
# 1. Drupal
# ====================
RUN mkdir -p $DOCKER_BUILD_HOME
#Add your code to /home/drupal_prj
ADD ./drupal-src ${DRUPAL_PRJ}entrypoint.sh
En este archivo, la función setup_drupal estaba recuperando el código fuente de un repositorio git, entre otras tareas. Lo he modificado para que simplemente recupere el código que copié en el archivo Dockerfile, ajuste los permisos (me volví loca con las imágenes) y utilice drush rebuild para reconstruir la cache y que no pasen cosas raras (me volví loca con los estilos).
#Get drupal from your code
setup_drupal(){
cd $DRUPAL_PRJ
chmod a+w "$DRUPAL_PRJ/web/sites/default"
if [ -e "$DRUPAL_PRJ/web/sites/default/settings.php" ]; then
#Test this time, if application settings are set to a personal git, myabe drupal has already installed in repo.
echo "INFO: Settings.php is exist..."
else
echo "INFO: Settings.php isn't exist..."
mkdir -p "$DRUPAL_PRJ/web/sites/default/files"
cp "$DRUPAL_PRJ/web/sites/default/default.settings.php" "$DRUPAL_PRJ/web/sites/default/settings.php"
fi
chmod a+w "$DRUPAL_PRJ/web/sites/default/files"
chmod a+w "$DRUPAL_PRJ/web/sites/default/settings.php"
while test -d "$DRUPAL_HOME"
do
echo "INFO: $DRUPAL_HOME is exist, clean it ..."
chmod 777 -R $DRUPAL_HOME
rm -Rf $DRUPAL_HOME
done
echo "Composer install --no-dev"
composer install -o --no-dev --no-interaction
echo "Giving write permissions to $DRUPAL_PRJ/web/sites/default/files/"
chmod -R 777 "$DRUPAL_PRJ/web/sites/default/files/"
echo "Rebuild cache (drush rebuild)..."
drush rebuild
echo "Clean generated images (drush "
ln -s $DRUPAL_PRJ/web $DRUPAL_HOME
}El resto de archivos se quedan igual que en el ejemplo de GitHub.
Despliegue con Azure DevOps
Lo siguiente que he hecho ha sido subir a GitHub mi código fuente y me he creado un proyecto dentro de Azure DevOps para poder gestionar la integración continua y el despliegue continuo:
Pipeline para la build
La pipeline de build sería como la siguiente:

Como estoy trabajando con contenedores de Docker, necesito como mínimo estas dos tareas. A esta pipeline le he asociado el repositorio de GitHub y he utilizado un agente de Linux hosteado por Azure DevOps.
Build an image

La imagen se genera con el archivo Dockerfile del código fuente y he elegido un Container Registry en Azure como repositorio para mis imágenes. La razón por la cual necesito especificarlo ahora es para que me etiquete la imagen de manera correcta, y automática 🙂
Push an image

Una vez que la imagen se ha creado correctamente en el agente, el siguiente paso es subirla al ACR, donde utilizo el mismo que en el paso anterior y simplemente hago push.
Pipeline para la release
En este ejemplo he creado una pipeline con un único stage:

Bash Script
Es interesante que sepas que puedes tener ciertas tareas en Azure DevOps que luego puedes desactivar. En este caso, la primera solamente la estaba usando para comprobar que la variable Build.BuildId está disponible, ya que no quiero sobrescribir la imagen una y otra vez sino que prefiero tener una nueva imagen por cada build y así tenerla versionada por si necesito dar un paso atrás.
Deploy in staging slot to warm up
Esta tarea va a desplegar mi nueva imagen, con mi proyecto de Drupal 8, en el slot llamado staging, para que pueda hacer un precalentamiento del sitio y cambiar después al slot de producción. En ella debo personalizar los siguientes valores:

Por otro lado, en el apartado Application and Configuration Settings debes almacenar los siguientes valores para poder conectarte a tu ACR:
- DOCKER_REGISTRY_SERVER_URL: puedes encontrar la URL de tu ACR en el apartado Overview del mismo.
- DOCKER_REGISTRY_SERVER_USERNAME: se encuentra en Access Keys.
- DOCKER_REGISTRY_SERVER_PASSWORD: también en el apartado Access Keys.

En esta tarea también he configurado la variable de salida AppServiceApplicationUrl para poder recuperarla en la siguiente:

Web Url
Lo mismo que en anterior bash, sólo lo he usado para comprobar que Staging.AppServiceApplicationUrl tiene el valor de la URL de staging,que siempre viene bien un poco de debugging 😀
Wait for 2 minutes

Me descargué esta tarea desde el marketplace, en la que simplemente espero 2 minutos para que le dé tiempo al contenedor a arrancar.
Warmup staging slot

Otra tarea más del marketplace que me ayudará en el proceso de precalentamiento del sitio, pasándole como variable la URL del entorno de staging y los paths a los que quiero que haga una llamada.
Swap to production

Por último, una vez que el entorno de staging está listo, hago el swap con producción. Cuando finalice todo el proceso, si accedes a la URL de tu App Service deberías de ver tu Drupal funcionando.
Cómo ver los logs
Te recomiendo que habilites los logs de App Service en el apartado Monitoring > App Service logs.

Después, haz clic en Go en la sección Advanced Tools:

Accederás al portal Kudu donde podrás ver tus logs en el apartado Log Stream:

¡Saludos!

Hola Gisela, gracias por el artículo; nos ha servido muchísimo. Tenemos una consulta sobre el uso de Azure Blob Storage en conjunto con el Drupal; debido a que al ser un container entonces se perderían los archivos (imágenes, etc.) y demás que los usuarios suben al CMS y que no quedan en la base de datos de Azure SQL. ¿Sabe de algún Drupal module o library de Microsoft Azure que recomiendes para implementar dicha integración? Hemos buscado varias opciones pero aún no hemos dado con una solución.