En Mi Local Funciona

Technical thoughts, stories and ideas

Auto-escalado y sincronización de instancias públicas de Magnolia en AWS

Publicado por Antonio Miguel Pérez Rivera el

ECMMagnoliaAmazon AWS

En este post describiremos la operativa necesaria para implementar una estructura que permita el auto-escalado de instancias públicas de Magnolia utilizando los servicios de Amazon Web Services.

El esquema básico de un entorno productivo en Magnolia consta de dos tipos de instancias:

  • Una instancia de Authoring o instancia de edición, encargada de centralizar toda la edición de contenido por parte de los usuarios.
  • "N" instancias públicas, encargadas de servir el contenido al exterior.

El objetivo es que la instancia de Authoring proporcione todo el contenido publicado a una instancia recién creada de forma totalmente automática, es decir, que la nueva instancia levantada se sincronice con ésta. Para ello, el grupo de auto-escalado (Auto Scaling Group, ASG) será el encargado de determinar cuándo es necesario levantar una nueva instancia pública.

Al encender o apagar una nueva instancia, enviará un mensaje a través del sistema de notificación SNS que disparará a su vez la ejecución de una función Lambda que, dependiendo del tipo de evento (autoscaling:EC2_INSTANCE_LAUNCH ó autoscaling:EC2_INSTANCE_TERMINATE) dará de alta la nueva instancia pública creada como suscriptora de la instancia de Authoring y disparará la sincronización de contenido, o eliminará ésta de la lista de suscriptores.

El esquema de la solución es el siguiente:


Creación de la configuración de lanzamiento

Lo primero que debemos hacer es acceder a la consola de Amazon Web Services con los credenciales proporcionados y crear una configuración de lanzamiento para nuestro grupo de auto-escalado.

Para ello debemos acceder a la sección "EC2" y a continuación a "Launch configurations". Una vez hayamos llegado a la pantalla donde se muestran todas las configuraciones de lanzamiento seleccionamos "Create a new launch configuration" para crear una nueva:

El siguiente paso será seleccionar una de las AMIs creadas. Para este proyecto concreto, se configuró una instancia pública con todo lo necesario para ejecutar esta prueba: Scripts de inicialización, configuración de AWS CLI y despliegue de un bundle de Magnolia (En concreto, de la versión 5.7 EE Std).

La AMI creada es ECM-PUBLIC-AWS-MAGNOLIA, por tanto es la que debemos elegir como AMI de nuestro nuevo grupo de auto-escalado.

A la hora de escoger el tipo de instancia, podremos seleccionar varios, como se puede observar en la imagen. Sin embargo, para garantizar el buen funcionamiento de Magnolia, debemos elegir una instancia igual o superior a la t2.medium que se muestra seleccionada:

Pulsamos en "Next step" y nos aparecerá la pantalla de selección de detalles de la configuración de lanzamiento. En este punto existen varios requisitos que debemos cumplir para que la prueba funcione correctamente:

  • Que la configuración de lanzamiento tenga un rol válido asociado (En nuestro caso at-ecm-role)

  • Que especifiquemos en el recuadro de "User data" que se ejecute el script de inicialización creado para tal propósito dentro de la máquina:

Este script de inicialización crea una nueva tabla en la instancia RDS con el identificador de la instancia EC2 recién levantada como nombre, actualiza el contexto del servidor con la dirección de dicha tabla y guarda la dirección IP de la instancia de Author en un fichero de texto en la máquina.

En el siguiente paso será necesario configurar el almacenamiento de la máquina. Para todas las pruebas realizadas hemos elegido el mismo tipo de almacenamiento que se muestra:

El siguiente y último paso será el de elegir los Security Groups para la configuración de lanzamiento. Para esta prueba hemos escogido los siguientes:

Una vez hayamos seleccionado los grupos de seguridad adecuados, pulsaremos en "Review" y en "Create Launch Configuration" para su creación.

Creación y configuración del balanceador de carga

Como podemos observar en el gráfico de la arquitectura de la solución, necesitaremos un balanceador de carga que se encargue de distribuir todo el tráfico entre las distintas instancias públicas presentes. Para configurar este balanceador de carga primero debemos determinar cómo se comunicará AWS con nuestras instancias de Magnolia para realizar el healthcheck pertinente.

La solución por la que hemos optado, en este caso, pasa por la creación de una página dentro del workspace "pages" llamada, literalmente, "healthcheck", la cual será accedida por el balanceador de carga para determinar si la instancia está sana o no. Esta página se propagará automáticamente a las instancias públicas en el momento de la sincronización.

Para crear nuestro balanceador de carga debemos acceder a "EC2 > Load balancers" y pulsar en el botón "Create new load balancer". Se nos mostrará la siguiente pantalla:

En esta pantalla debemos seleccionar el "Classic Load Balancer" frente al "Application Load Balancer", ya que no tenemos diferentes Target Groups y la funcionalidad ofrecida por éste es suficiente para esta prueba de concepto (Además, su configuración es mucho más sencilla).

Tras informar nuestra VPC y nuestros grupos de seguridad, llegaremos a la pantalla de configuración del healthcheck, donde debemos introducir los siguientes datos:

  • Ping target: HTTP:8080/magnoliaPublic/healthcheck
  • Timeout: 5 seconds
  • Interval: 300 seconds
  • Unhealthy Threshold: 5
  • Healthy Threshold: 10

Creación y configuración de grupos de auto-escalado

La entidad que disparará tanto la creación de una nueva instancia pública como la eliminación de ésta es el grupo de auto-escalado. Un grupo de auto-escalado contiene un conjunto de instancias EC2 que comparten características similares y se tratan como grupos lógicos para el escalado y la administración de las instancias.

Un ASG comienza lanzando suficientes instancias EC2 para satisfacer su capacidad deseada. Además, el ASG mantiene este número de instancias realizando comprobaciones de estado periódicas en las instancias del grupo. Si una instancia pasa a tener un estado incorrecto, el grupo termina la instancia en mal estado y lanza otra instancia para sustituirla.

Para crear un nuevo grupo de auto-escalado, debemos acceder a la consola de AWS y navegar hasta la pestaña "EC2":

Una vez nos encontremos dentro del "EC2 Dashboard", debemos navegar en el menú lateral hasta encontrar el enlace de "Auto Scaling Groups" y pulsarlo. Al hacerlo, se nos mostrará la siguiente pantalla:

Pulsamos en "Create Auto Scaling Group" para crear un grupo nuevo, lo que nos llevará a la siguiente pantalla:

Elegimos nuestra Launch Configuration recien creada y pulsamos en "Next Step", lo que nos llevará a la pantalla de introducción de los datos de nuestro nuevo grupo de auto-escalado. Debemos tener ciertos puntos en cuenta a la hora de poblar este formulario:

  • La red debe ser la misma que la red donde se sitúan nuestras instancias EC2.
  • La subred debe ser, también, la misma.

La configuración del grupo quedaría como sigue:

Una vez seleccionada red, subred y nombre del ASG podemos navegar directamente hasta la pestaña "Review" y crear el grupo de auto-escalado, ya que la configuración restante la realizaremos desde la pestaña de edición. Cuando el grupo aparezca en la lista, lo seleccionaremos y pulsaremos en "Edit" tal y como se muestra en la figura:

En la pestaña de edición, navegaremos hasta la pestaña "Tags" y añadiremos los siguientes:

  • AuthorIpAddress: Dirección IP Privada de la instancia de Authoring.
  • Name: at-ecm-Magnolia-public (Por defecto).
  • Project: ATSI0055 (Por defecto).

Es importante que a la hora de dar de alta las etiquetas, seleccionemos también "Tag new instances", ya que necesitaremos que estas etiquetas se propaguen a las instancias EC2 creadas.

Una vez hecho ésto, debemos incluir nuestro balanceador de carga desde "Classic Load Balancers":

Por ahora, y hasta que no creemos los roles y topics SNS, será suficiente con esta configuración para el ASG.

SNS: Simple Notification Service

Amazon SNS (Simple Notification Service) es un servicio de notificaciones móviles y mensajes de publicación/suscripción completamente administrado para coordinar la entrega de mensajes a clientes y puntos de conexión suscritos. Dentro del SNS podemos crear "topics", que pueden definirse como canales de comunicación para enviar mensajes y suscribirse a notificaciones.

En nuestro caso, necesitaremos tres topics:

  • IP-INSTANCES-TOPIC: Topic por el que se notificará las IP, tanto de la instancia de Authoring como de la instancia pública.
  • SNS-INSTANCE-START: Topic por el que se notificará cuando una instancia EC2 se levante.
  • SNS-INSTANCE-STOP: Topic por el que se notificará cuando una instancia EC2 se caiga finalmente.

Para crear nuestros topics, debemos navegar hasta "SNS" y pulsar en el botón "Create new topic":

Una vez creado, nos mostrará el ARN (Identificador) del topic, que nos será útil posteriormente.

Roles para los topics de SNS

Para conseguir la funcionalidad deseada en este proyecto es necesario que nuestro grupo de auto escalado sea capaz de publicar mensajes en los topics de SNS recién creados cuando las instancias arranquen o se paren.

Para ello, debemos darle permiso a nuestro grupo de auto escalado para acceder a los topics. Ésto lo haremos a través de la "IAM Management console": Crearemos un nuevo rol (Al que llamaremos TEST-ROLE) y le añadiremos las siguientes políticas:

Creación y configuración de las notificaciones en ASG

Una vez tengamos la configuración de los topics SNS y el rol creado, podemos finalizar la configuración de nuestro ASG especificando las notificaciones SNS que se van a enviar en cada caso.

A la hora de crear estas notificaciones, el proceso es sencillo. Debemos acceder a "EC2 > Auto Scaling" y editar el grupo de auto escalado creado previamente. En la pestaña "Notifications" debemos añadir las notificaciones que consideremos oportunas.

Para crear una notificación, pulsamos en el botón "Create Notification" y cumplimentar el formulario con el destino de la información y el tipo de evento sobre el que reaccionará de la siguiente forma:

Como podemos observar en la figura, tendremos una notificación SNS que se enviará cuando una instancia se encienda o se apague. Esta notificación se enviará a través de un topic SNS a una función Lambda que determinará la IP privada de las instancias y enviará esta información a un topic SNS u otro dependiendo del evento que se haya producido, con el objetivo de que sean consumidas por las funciones Lambda correspondientes.

Funcionalidad requerida de las funciones Lambda

Antes de proceder a la creación de las dos funciones Lambda necesarias, haremos un breve repaso por la estructura de Magnolia, a fin de ser capaces de determinar exactamente qué funcionalidad deben cubrir estas funciones para el correcto funcionamiento de esta prueba de concepto:

Aquí podemos observar cómo existen dos tipos de instancias: Las instancias de Authoring y las instancias Públicas, que son las encargadas de dar servicio al exterior. Un contenido dado de alta en una instancia de Author no llegará a estar disponible en las instancias públicas si no se ha publicado dicho contenido.

Para que una instancia pública recién creada se suscriba al flujo de publicación de contenidos de una instancia de Author es necesario que se dé de alta la instancia pública como un "suscriptor" en la máquina de Author. En la siguiente figura podemos observar como la instancia guarda sus suscriptores:

La funcionalidad que necesitamos que cumpla nuestra función Lambda será la de dar de alta un suscriptor nuevo en la instancia de Author con la dirección IP privada de nuestra nueva instancia EC2 levantada. Para ello, haremos uso de la API REST de Magnolia (En concreto, de su endpoint "nodes") para crear un nuevo nodo de contenido bajo "receivers" con la dirección de nuestra EC2 recién creada.

Por otra parte, tendremos otra función Lambda que se ejecutará cuando la instancia se pare, que se limitará a usar el endpoint "properties" de la API REST de Magnolia para cambiar el valor de la propiedad "enabled" a "false" y así dar de baja a la instancia de la lista de suscriptores.

Además de estas funciones Lambda, tendremos otra que se encargará de realizar peticiones a las funciones "describe-instances" y "describe-tags", con el objetivo de determinar las IP de las instancias y las etiquetas asociadas a estas, y proporcionar esta información a las demás a fin de no tener que hacer uso de una puerta de enlace NAT.

Creación y configuración de las funciones Lambda

Podemos definir AWS Lambda como un servicio que permite ejecutar código sin aprovisionar ni administrar servidores. Existen varios lenguajes de programación con el que podemos implementarlas:

  • NodeJS
  • Java
  • C#
  • Go
  • Python

En este caso concreto hemos elegido Java para ser el lenguaje en el que implementaremos nuestras funciones por estar mucho más familiarizados con él que con el resto de los que se especifican.

Para hacerlo, lo hemos hecho desde nuestro propio IDE (Eclipse JEE Oxygen 2) usando el plugin de AWS Toolkit:

Puede encontrar más información sobre versiones e instalación en su web oficial: https://aws.amazon.com/es/eclipse/

Usando este plugin, lo que debemos hacer es crear un nuevo proyecto de tipo "AWS Lambda Java Project". Una vez que lo seleccionemos, debemos rellenar este formulario y se creará una clase llamada "LambdaFunctionHandler", en cuyo método "handleRequest" debemos implementar la lógica a ejecutar cuando recibamos una notificación a través del SNS.

Una vez implementada la lógica de las funciones Lambda, el proceso para su subida a AWS pasa por hacer 'click' con el botón secundario en el IDE y seleccionar "AWS Lambda" > "Upload function to AWS Lambda".

Si seleccionamos esta función, se nos abrirá la siguiente pantalla:

Hacemos click en "Next" y nos abre la siguiente pantalla, donde tenemos que introducir el rol que se asociará a la función Lambda y el bucket de Amazon S3 donde se alojará el código:

Una vez hecho esto para ambas funciones, éstas quedarán subidas a AWS, pero aún no se podrían ejecutar en ningún caso, al requerir alguna configuración adicional. Esta configuración la haremos desde la consola de AWS, accediendo a "AWS Lambda" y seleccionando una de las recientemente creadas:

Lo primero que debemos tener en cuenta es que debemos especificar el topic SNS que desencadenará la ejecución de esta Lambda, para ello seleccionaremos "SNS" de la lista de la izquierda e introduciremos nuestro topic (Recordemos, SNS-INSTANCE-START para la Lambda que añade el suscriptor a la instancia de Author y SNS-INSTANCE-STOP para la que lo da de baja). Una vez hecho esto guardamos la configuración haciendo click en el botón "Guardar" presente en la esquina superior derecha.

Para terminar de configurar nuestras funciones Lambda en las que sea necesario comunicarnos con instancias EC2, debemos volver a "AWS Lambda", seleccionar nuestra función y habilitar el VPC de la siguiente forma:

Pulsamos en "Guardar" en la esquina superior izquierda y nuestras funciones Lambda han quedado correctamente configuradas.

Prueba de la solución

Partimos de la siguiente situación: Tenemos una instancia de EC2 llamada "at-ecm-Magnolia-author" en cuyo interior está ejecutandose la instancia de Authoring, y tenemos, por otra parte, a nuestro grupo de auto-escalado que irá activando o parando instancias según se requieran.

Podemos observar, además, que dicha instancia de Author no tiene ningún suscriptor dado de alta y que hay contenido listo para sincronizar con las nuevas instancias:

Aumentamos en "1" el parámetro "Desired Capacity" en el grupo de auto-escalado y esperamos unos segundos para que Magnolia se instale y se sincronice todo el contenido deseado:

Podemos observar, además, cómo se ha dado de alta un nuevo suscriptor en la instancia de Author:

Si, por el contrario, hacemos la prueba al contrario (Es decir, disminuyendo en "1" el parámetro Desired Capacity del ASG) nos parará la instancia Public que acabamos de sincronizar, y dará de baja el suscriptor en la instancia de Author:

Espero que este post os haya resultado de interés.

¡Síguenos en Twitter para estar al día de nuevos posts y charlas en nuestros grupos de Meetup (por ahora Madrid y Barcelona)!