Integrar Drupal 8 con Azure Cache for Redis

Si estás pensando en subir tu Drupal a Microsoft Azure lo más seguro es que también vayas a hacer uso de una cache externa para mejorar su rendimiento. En este artículo quiero contarte cómo integrar el Drupal 8 que subí ayer en Web Apps for Containers con Azure Cache for Redis.

Crear un recurso de Azure Redis for Cache

Para crear este servicio puedes lanzar el siguiente comando:

#Variables
LOCATION="northeurope"
REDIS_NAME="returngis"
RESOURCE_GROUP="Drupal-WebApp-For-Containers"

#Azure login
az login

#Create Azure Cache for Redis
az redis create  --name $REDIS_NAME --location $LOCATION \
--resource-group $RESOURCE_GROUP \
--sku Standard --vm-size C1 \
--enable-non-ssl-port

O desde el portal de Azure hacer clic en Create a resource y buscar por Azure Cache for Redis:

Crear un nuevo recurso de cache desde el portal

Instalar extensión PHP para Redis

Para poder utilizar el módulo de Redis necesitas tener instalada la extensión para PHP. En el ejemplo anterior, donde Drupal 8 se está ejecutando en un contenedor de Docker en App Service, puedes instalarla cambiando tu Dockerfile. Aquí te dejo el fragmento que he modificado del ejemplo:

RUN set -ex \
# --------
# ~. essentials
# --------
# ~. PHP extensions
# --------
# install the PHP extensions we need
# postgresql-dev is needed for https://bugs.alpinelinux.org/issues/3642
&& docker-php-source extract \
    && apk add --no-cache --virtual .build-deps \
#1. I need it to install pecl
autoconf g++ make \
libjpeg-turbo-dev \
libpng-dev \
        libzip-dev \
zip \
        freetype-dev \
#2. I use pecl to install redis
&& pecl install redis \                  
&& docker-php-ext-configure zip --with-libzip \
&& docker-php-ext-configure gd \
--with-freetype-dir=/usr/include/ \
--with-jpeg-dir=/usr/include/ \
--with-png-dir=/usr/include/ \
&& docker-php-ext-install -j "$(nproc)" \
gd \
zip \
#3. I enable redis
&& docker-php-ext-enable redis \
&& runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)" \
&& apk add --virtual .drupal-phpexts-rundeps $runDeps \
&& apk del .build-deps \
&& docker-php-source delete \
    # session_save_path
    && mkdir -p /usr/local/php/tmp \
    && chmod 777 /usr/local/php/tmp \
# -------------
# 1. Drupal
# -------------
    && mkdir -p ${DRUPAL_SOURCE}\
# ----------
# 2. composer
# ----------
&& curl -sS $COMPOSER_DOWNLOAD_URL | php -- --install-dir=/usr/bin --filename=composer \
&& composer self-update \
# ----------
# 3. drush
# ----------
    && rm -rf /home/.composer && export COMPOSER_HOME='/root/.composer/' \
    && composer global require consolidation/cgr \
&& composer_home=$(find / -name .composer) \
    && ln -s $composer_home/vendor/bin/cgr /usr/local/bin/cgr \
&& cgr drush/drush \
    && ln -s $composer_home/vendor/bin/drush /usr/local/bin/drush \
# ----------
# 4. varnish
# ----------
    && apk update \
    && apk add --no-cache varnish\
    && rm -rf /var/log/varnish \
&& ln -s $VARNISH_LOG_DIR /var/log/varnish \
# ----------
# ~. clean up
# ----------
&& apk upgrade \
&& rm -rf /var/cache/apk/* \
&& rm -rf $DOCKER_BUILD_HOME \
&& rm -rf /etc/nginx/conf.d/default.conf 

Como puedes ver, he instalado las dependencias autoconf g++ make, luego he instalado Redis a través de pecl install redis y por último he habilitado la extensión a través de docker-php-ext-enable redis.

Instalar el módulo de Redis en Drupal

Para instalar el módulo de Redis lo he hecho desde mi código fuente con composer:

composer require drupal/redis

Lo siguiente que necesitas es configurar el archivo web/sites/default/settings.php con los parámetros de Azure Cache for Redis:

/** Azure Cache for Redis configuration 
 * Set redis configuration.
 *//** @see: https://docs.platform.sh/frameworks/drupal8/redis.html */
if (extension_loaded('redis')) {

  // Set Redis as the default backend for any cache bin not otherwise specified.
  // $settings['cache']['default'] = 'cache.backend.redis';
  $settings['redis.connection']['interface'] = 'PhpRedis'; // Can be "Predis".
  $settings['redis.connection']['host'] = 'YOUR_DNS_NAME.redis.cache.windows.net';
  $settings['redis.connection']['port'] = '6379';
  $settings['redis.connection']['password'] = "PRIMARY_ACCESS_KEY"; 

  // Apply changes to the container configuration to better leverage Redis.
  // This includes using Redis for the lock and flood control systems, as well
  // as the cache tag checksum. Alternatively, copy the contents of that file
  // to your project-specific services.yml file, modify as appropriate, and
  // remove this line.
  $settings['container_yamls'][] = 'modules/contrib/redis/example.services.yml';

  // Allow the services to work before the Redis module itself is enabled.
  $settings['container_yamls'][] = 'modules/contrib/redis/redis.services.yml';

  // Manually add the classloader path, this is required for the container cache bin definition below
  // and allows to use it without the redis module being enabled.
  $class_loader->addPsr4('Drupal\\redis\\', 'modules/contrib/redis/src');

  // Use redis for container cache.
  // The container cache is used to load the container definition itself, and
  // thus any configuration stored in the container itself is not available
  // yet. These lines force the container cache to use Redis rather than the
  // default SQL cache.
  $settings['bootstrap_container_definition'] = [
    'parameters' => [],
    'services' => [
      'redis.factory' => [
        'class' => 'Drupal\redis\ClientFactory',
      ],
      'cache.backend.redis' => [
        'class' => 'Drupal\redis\Cache\CacheBackendFactory',
        'arguments' => ['@redis.factory', '@cache_tags_provider.container', '@serialization.phpserialize'],
      ],
      'cache.container' => [
        'class' => '\Drupal\redis\Cache\PhpRedis',
        'factory' => ['@cache.backend.redis', 'get'],
        'arguments' => ['container'],
      ],
      'cache_tags_provider.container' => [
        'class' => 'Drupal\redis\Cache\RedisCacheTagsChecksum',
        'arguments' => ['@redis.factory'],
      ],
      'serialization.phpserialize' => [
        'class' => 'Drupal\Component\Serialization\PhpSerialize',
      ],
    ],
  ];

  /** Optional prefix for cache entries */  $settings['cache_prefix'] = 'drupal_';

  /** @see: https://pantheon.io/docs/redis/ */  // Always set the fast backend for bootstrap, discover and config, otherwise
  // this gets lost when redis is enabled.
  $settings['cache']['bins']['bootstrap'] = 'cache.backend.chainedfast';
  $settings['cache']['bins']['discovery'] = 'cache.backend.chainedfast';
  $settings['cache']['bins']['config'] = 'cache.backend.chainedfast';

  /** @see: https://github.com/md-systems/redis */  // Use for all bins otherwise specified.
  $settings['cache']['default'] = 'cache.backend.redis';

  // Use this to only use it for specific cache bins.
  $settings['cache']['bins']['render'] = 'cache.backend.redis';

  // Use for all queues unless otherwise specified for a specific queue.
  $settings['queue_default'] = 'queue.redis';

  // Or if you want to use reliable queue implementation.
  $settings['queue_default'] = 'queue.redis_reliable';

  // Use this to only use Redis for a specific queue (aggregator_feeds in this case).
  $settings['queue_service_aggregator_feeds'] = 'queue.redis';

  // Or if you want to use reliable queue implementation.
  $settings['queue_service_aggregator_feeds'] = 'queue.redis_reliable';
}

Como valores propios de tu servicio de redis necesitas el host, el cual puedes recuperar del apartado Overview, y la primary access key del apartado Access Keys.

Comprobar que está funcionando correctamente

Ahora localiza el módulo de Redis en el apartado Extend:

Seleccionalo y haz clic en Install.

Para comprobar que el cliente de Redis se ha conectado de manera satisfactoria a tu servicio, en Reports > Status report busca la línea de REDIS y comprueba que está todo correcto.

El módulo de Redis aparece conectado

Por último, puedes acceder a la consola de Redis directamente desde el portal de Azure:

Acceso a la consola de Redis

y hacer algunas comprobaciones:

keys *
info clients
monitor

El resultado será parecido al siguiente:

Redis Console en Azure Cache for Redis

¡Saludos!