Cluster de servidores web usando sistemas de archivos compartidos con eZ Platform

Carlos Revillo
The Cocktail Engineering
8 min readOct 22, 2018

--

Nuestros clientes suelen necesitar entornos de alta disponibilidad desde los que servir sus sites. Estos entornos deben estar preparados para aguantar picos de carga, así como para ser capaces de seguir dando servicio ante un inoportuno fallo de hardware.

La solución más común en estos casos es usar un “cluster”. Podemos definir un cluster como un conjunto de ordenadores unidos mediante una red de alta velocidad que de cara al exterior funcionan como uno solo.

Un caso de uso bastante común es el de tener dos o más servidores webs detrás de uno (o varios) balanceadores de carga:

Cuando trabajamos en una arquitectura de estas características necesitamos que todos los nodos que tenemos en el cluster trabajen siempre con la misma versión de código. Es decir, cada vez que hacemos una subida a producción tenemos que estar seguros de que esos cambios en nuestros archivos sean enviados a todas las máquinas que conforman ese cluster.

Para que esto sea posible se escriben procesos de despliegue que se encargan, entre otras cosas, de colocar esa nueva versión del código en cada uno de los frontales. Ahora bien, ¿qué ocurre con aquellos elementos que van a ser contribuidos por los editores o bien se tratan de contenidos generados por los usuarios del site? Pensemos en cualquier CMS desde el que se suban imágenes para los artículos o en una aplicación pensada para recibir currícula de personas interesadas en trabajar en nuestra empresa.

Cada petición recibida será atendida por uno y solo uno de los frontales expuestos en la arquitectura. Por tanto, si no hacemos algo más, tendremos que esa imagen solo estará disponible en el directorio de archivos del frontal que ha recibido esa petición. Tendríamos algo así:

Es decir, a la hora de pedir una imagen, el balanceador enviaría la petición a uno de los frontales. Ese frontal devolverá un código 200 si tiene la imagen, pero también devolverá un 404 si no la tiene.

Se hace por tanto necesaria una pieza en la que tengamos todas nuestras imágenes y que sea “accessible” desde cada uno de nuestros frontales:

Este sistema de archivos compartido puede ser un NFS, un NAS, o también un almacenamiento en la Nube como el que nos ofrece Amazon o Google Cloud.

Configurando eZ Platform para usar un sistema de ficheros compartido

Una de las muchas funcionalidades que eZ Platform incluye en su core es la posibilidad de usar un sistema de ficheros compartidos sin necesidad de desarrollar ningún código adicional.

eZ Platform cuenta con varios mecanismos de manejo de ficheros binarios. Toda la api de entrada y salida de archivos, en adelante IO API, está organizada en dos tipos de manejadores que son usados por el IO Service (servicio de entrada y salida);

  • eZ\Publish\IO\IOMetadataHandler:Se encarga de almacenar y consultar metadatos de los archivos (tamaño, validez…)
  • eZ\Publish\IO\IOBinarydatHandler: Se encarga de almacenar y cargar los archivos en sí.

Para trabajar con archivos, eZ hace uso de la librería Flysystem. Esto le permite no solo trabajar con distintos sistemas de almacenamiento sino también la posibilidad de cambiar de un sistema a otro en cualquier momento del ciclo de vida del proyecto.

Por defecto, eZ usa el Local Adapter. Esto es, cuando una imagen o archivo se sube a la aplicación quedará alojado en una carpeta del servidor que ejecuta la petición.

El manejador DFS Cluster

Para trabajar con un cluster, eZ Platform provee también un manejador de metadatos propio llamado “DFS Cluster”. Se basa en una tabla de una base de datos donde se va a almacenar información relativa al archivo (nunca el archivo en sí). Este mecanismo fue añadido a la aplicación ya que es más rápido acceder a la información si estaba almacenada en la base de datos que si se consultaba directamente al NFS o al almacenamiento en la nube definido.

Configurando el manejador DFS

eZ Platform provee además un archivo de configuración que puede servir como base para tu proyecto. Consta de 4 partes bien diferenciadas:

  • Configuración de la conexión dfs: En entornos de producción es recomendable usar una base de datos adicional para guardar esta información. En cualquier caso, puede usarse la misma ya que la instalación de eZ Platform ya incluye esa tabla.
  • Definir el manejador de Flysystem: Por defecto configurado pensado en que estés utilizando un NFS.
  • Definir los manejadores de eZ: Normalmente solo necesitarás cambiar el binarydata_handler.nfs.flysystem.adapter
  • Configurar los manejadores para la aplicación.

Usando S3 como sistema de archivos compartido

Como ejemplo vamos a configurar nuestro eZ para trabajar con un bucket de eZ Platform. Estos son los pasos a realizar:

Ya que vamos a trabajar con S3 necesitamos incluir en nuestra aplicación el adaptador para S3 de la librería Flysystem. Podemos hacerlo con composer. composer require league/flysystem-aws-s3-v3

Definir el cliente que se encargará de enviar y obtener las imágenes desde el S3. Puede ser un servicio que incluyamos en nuestro archivo services.yml

Seguidamente, definimos un nuevo adaptador para Flysystem que va a usar el cliente que acabamos de definir

Ahora podemos añadir un nuevo manejador de binarios que use el adaptador que acabamos de crear. Le vamos a dar el identificador awss3 y usará el adaptador definido en el paso anterior

Finalmente, configurar la aplicación para que use esos manejadores.

El resultado: Todas las imágenes que a partir de ahora subamos desde el administrador quedarán almacenadas en el bucket de Amazon. Lo podemos ver en este vídeo.

Pero no hemos terminado aún con todo el trabajo. Si bien hemos visto que la imagen está subida al Bucket de Amazon, parece que no se está mostrando en el administrador tal y como se ve en la siguiente captura:

Si observamos el código fuente de esa página veremos que la ruta de esa imagen que no se está mostrando es de la forma http://host/var/site...

Es decir, el servidor está intentando buscar la imagen en el mismo disco donde tenemos la aplicación y no en el servicio S3 de AWS. Para solucionar esto, debemos activar unas reglas de escritura adicionales en el servidor web. eZ nos da ya estas reglas de tal forma que si usas sus plantillas para crear los VirtualHost (ya sean con Nginx o con Apache) te sirva como descomentar una línea.

En Nginx la regla a añadir es la siguiente:

rewrite “^/var/([^/]+/)?storage/images(-versioned)?/(.*)” “/app.php” break;

O lo que es lo mismo, ahora, cuando Nginx reciba como petición una de las rutas donde están las imágenes, las redirigirá al controlador principal de la aplicación. El controlador se encargará entonces de ver qué manejador de binarios está definido y de buscar el binario usando ese manejador.

De igual forma, a la hora de hacer miniaturas de imágenes, éstas también quedarán alojadas en el Bucket sin necesidad de desarrollos adicionales por nuestra parte.

Ahora sí, podremos ver las imágenes que han sido subidas al bucket.

Moviendo las imágenes y otros archivos a otro sistema

En este ejemplo hemos partido de un proyecto que va a empezar a desarrollarse. Pero, ¿qué ocurre si durante unos meses no se contempló la posibilidad de añadir varios frontales y queremos añadirlos ahora? O, ¿qué ocurriría si decidimos dejar Amazon para trabajar con Google Cloud o Azure?

Durante esos meses, puede que miles de imágenes hayan sido subidas desde el administrador de contenidos y sería un trabajo demasiado tedioso volver a subir esas imágenes al nuevo bucket una por una.

eZ Platform también ha pensado en esta posibilidad y nos ofrece un comando que definiendo una fuente y un destino nos permitirá mover las imágenes a otro sistema sin necesidad de escribir una sola línea de php.

Supongamos entonces que en nuestro proyecto vamos a dejar de trabajar con el bucket de Amazon S3 y usar uno de Google Cloud Storage.

Si no lo hemos hecho anteriormente, instalar la librería que nos permitirá conectar nuestra aplicación eZ Platform (por tanto, Symfony) con GCloud composer require superbalist/flysystem-google-storage

Siguiendo la documentación del bundle que permite a Symfony usar esta librería, configuramos un servicio para el cliente de Google y otro para el bucket.

Añadimos un nuevo adaptador que trabajará con nuestro cliente y bucket de GCloud.

Definimos un nuevo manejador de binarios que usará este nuevo adaptador

Y en este punto podemos usar el comando provisto por eZ Platform para hacer la migración de archivos de un sistema a otro. El comando se puede ejecutar de la siguiente forma: bin/console ezplatform:io:migrate-files --from=<metadata_handler>,<binary_handler> --to=<metadata_handler>,<binary_handler>

El comando también tiene una opción que te permitirá comprobar que los distintos manejadores están activos y pueden ser usados. Así, el comando bin/console ezplatform:io:migrate-files --list-io-handlers producirá esta salida

Configured meta data handlers: dfs, default
Configured binary data handlers: awss3, gcloud, default

Por tanto, para pasar los archivos desde el bucket de Amazon S3 al bucket de GCloud ejecutaríamos

bin/console ezplatform:io:migrate-files --from=dfs,awss3 --to=dfs,gcloud

El resultado lo podemos ver en el siguiente vídeo:

Finalmente, le decimos a eZ Platform que use “gcloud” como manejador de archivos binarios.

ezpublish:
system:
default:
io:
metadata_handler: dfs
binarydata_handler: gcloud

De esta forma podemos seguir usando esas imágenes sin necesidad de desarrollos adicionales ni de ningún tipo de regla adicional de re-escritura de urls.

De igual forma, y utilizando al configuración por entornos que permite cualquier aplicación Symfony, te será bastante sencillo testar tu código sin necesidad de contar con un bucket para tu entorno de test. En tu entorno de test ese manejador de binarios podría configurarse para usar un NFS, un FTP o cualquier otra cosa que estimes oportuna.

Conclusión

Flysystem es una librería de abstracción de sistemas de archivos para PHP. Provee un interfaz único para distintos sistemas de archivos, lo que permite el intercambio de información entre esos sistemas sin necesidad de desarrollos adicionales.

eZ Platform hace uso de esta librería para permitirnos almacenar nuestras imágenes y otro tipo de archivos en cualquiera que sea el sistema de almacenamiento escogido. Para mejorar el rendimiento, ofrece además un manejador de metadatos llamado DFS que puedes y debes usar cada vez que tu aplicación eZ Platform necesite ser ejecutada por más de un servidor web.

Además, ofrece un comando con el que se puede cambiar de sistema de almacenamiento escogido de forma rápida y sencilla.

--

--