Explorando App Mesh Parte 2: Conceptos, Demostración, Certificados y Observabilidad

Introducción

En la entrega anterior de este artículo, exploramos aspectos esenciales de AWS App Mesh. En esta segunda parte, nos sumergiremos en un ejemplo práctico para comprender su funcionamiento. Durante este ejercicio, nos centraremos en aspectos críticos, como la comunicación entre microservicios dentro de la malla App Mesh y cómo exponerlos al balanceador con un AWS Application Load Balancer (ALB) por medio de una puerta de entrada (Virtual Gateway).

¡Acompáñanos en este recorrido práctico!

Contexto

Para la demostración, emplearemos dos microservicios implementados en Node.js y Python. Estos microservicios exponen los siguientes APIs:

  • Api que invoca al otro servicio y le transmite un parámetro de tiempo de espera: /call_and_wait/[nombre_servicio_en_cloudmap]_[puerto]/[tiempo_de_espera]
  • Api que aguarda el tiempo especificado en el parámetro de la URL: /wait/[tiempo_de_espera]

Descripción de los parámetros:

  • nombre_servicio_en_cloudmap: Nombre del microservicio registrado en AWS Cloud Map.
  • puerto: Puerto del microservicio.
  • tiempo_de_espera: Tiempo en segundos para ejecutar un período de espera.

A continuación, detallaremos la secuencia de pasos a seguir para llevar a cabo la demostración:

Generar imágenes de los microservicios y almacenarlas en AWS ECR

Amazon Elastic Container Registry (ECR) es un servicio que proporciona un registro de contenedores seguro y completamente administrado en AWS.

Puesto que el enfoque principal de este artículo es la configuración de App Mesh, no profundizaré en el código de los microservicios. Por lo tanto, el código proporcionado es únicamente de referencia.

NodeJs:

const express = require("express");
const http = require("http");
...
app.get("/call_and_wait/:namespace/:wait_time", (req, res) => {
  const namespace = req.params.namespace;
  const waitTime = parseInt(req.params.wait_time, 10);
  let externalServiceUrl;


...
...

Python:
 

from flask import Flask
...
@app.route('/', methods=['GET'])
def status():
    return "OK"


@app.route('/wait/<int:wait_time>', methods=['GET'])
@xray_recorder.capture('wait_endpoint')
def wait(wait_time):
    time.sleep(wait_time)
    return f"Waited for {wait_time} seconds."
    app.run(host='0.0.0.0', port=5000, debug=False)
...
...

Después de compilar nuestras aplicaciones, procederemos a crear las imágenes correspondientes y cargarlas en AWS ECR mediante los comandos siguientes:
 

docker build -t <nombre_aplicacion> <path_dockerfile_aplicacion>
docker tag crystal-service:latest $<nombre_aplicacion>:local
docker push $<url_ecr>:local

Configurar servicios en AppMesh

Antes de proceder, crearemos la malla para nuestro ecosistema de microservicios. Es crucial destacar la configuración del filtro de salida, que para nuestro caso se configura a Allow external traffic, con lo que permitimos el tráfico externo.

{
  "meshName": "pxxx-local-appmesh",
  "spec": {
    "egressFilter": {
      "type": "ALLOW_ALL"
    }
  }
}

 

Estableceremos la configuración de nodos y servicios virtuales para cada uno de nuestros microservicios, tal como se ilustra a continuación:

Al establecer el nodo virtual, es esencial seleccionar AWS Cloud Map como método de descubrimiento de servicio. También, debemos configurar el puerto del listener y establecer los servicios backends para definir la comunicación entre microservicios. En nuestro escenario, no es necesario modelar los servicios backends, ya que estamos configurando la malla para permitir tráfico externo.

La configuración de nodo virtual es la siguiente:

{
  "meshName": "pxxx-local-appmesh",
  "virtualNodeName": "ms_python",
  "spec": {
    "serviceDiscovery": {
      "awsCloudMap": {
        "namespaceName": "pxxx.local",
        "serviceName": "ms_python",
        "attributes": []
      }
    },
    "listeners": [
	...
    ],
    "backends": [
      {
        "virtualService": {
          "virtualServiceName": "ms_nodejs.pxxx.local"
        }
      }
    ],
    "backendDefaults": {
      "clientPolicy": {}
    },
    "logging": {
      "accessLog": {
        "file": {
          "path": "/dev/stdout"
        }
      }
    }
  },
  "meshOwner": "XXXXXXXXX"

 

Ahora estableceremos el servicio virtual para ms_python, en donde seleccionaremos como proveedor un nodo virtual. En el caso de que necesitemos trabajar con dos versiones de un aplicativo, debemos crear un virtual router, con rutas a cada versión y seleccionar como proveedor el virtual router.

La configuración de servicio virtual es la siguiente:

{
  "meshName": "pxxx-local-appmesh",
  "virtualServiceName": "ms_python.pxxx.local",
  "spec": {
    "provider": {
      "virtualNode": {
        "virtualNodeName": "ms_python"
      }
    }
  },
  "meshOwner": "XXXXXXXXXXXX"
}

 

Virtual Gateway

Para habilitar el tráfico externo, específicamente desde un Load Balancer (ALB), es necesario crear un Virtual Gateway. En este, configuraremos los listeners correspondientes a nuestras aplicaciones y crearemos Gateway Routes para cada microservicio. Puedes encontrar la configuración detallada de nuestro Virtual Gateway a continuación:

{
  "meshName": "pxxx-local-appmesh",
  "virtualGatewayName": "pxxx-gateway",
  "spec": {
    "listeners": [
      {
        "portMapping": {
          "port": 5000,
          "protocol": "http"
        }
      },
      {
        "portMapping": {
          "port": 3000,
          "protocol": "http"
        }
      },
      {
        "portMapping": {
          "port": 80,
          "protocol": "http"
        }
      }
    ]
  },
  "meshOwner": "XXXXXXXXXXXXXXX"
}
  

 

Configurar y desplegar servicios en ECS

Antes de desplegar los servicios de nuestros microservicios en AWS ECS, es necesario construir la definición de tarea (Task Definitions) para cada uno. Los aspectos cruciales de dicha definición incluyen:

  • Especificar 3 contenedores en containerDefinitions: uno para la aplicación, otro para el envoy-proxy y para X-Ray.
  • Agregar la dependencia del contenedor envoy al contenedor de la aplicación.
"dependsOn": [
                {
                    "containerName": "envoy",
                    "condition": "HEALTHY"
                }
            ],
  • Configurar la variable de entorno APPMESH_RESOURCE_ARN en el contenedor envoy-proxy con el nombre del nodo virtual.
  • Permitir el envío de trazas a X-Ray configurando la variable ENABLE_ENVOY_XRAY_TRACING con el valor de 1.
 "environment": [
	{
		"name": "XRAY_DAEMON_PORT ",
		"value": "2000"
	},
	{
		"name": "APPMESH_RESOURCE_ARN",
		"value": "arn:aws:appmesh:eu-central-1:xxxxxx:mesh/pxxx-local-appmesh/virtualNode/ms_python"
	},
	{
		"name": "ENABLE_ENVOY_XRAY_TRACING",
		"value": "1"
	},
	{
		"name": "ENVOY_LOG_LEVEL",
		"value": "info"
	}
  ],
  • Configurar el proxyConfiguration para que el envoy-proxy pueda interceptar todas las solicitudes entrantes a nuestros microservicios.
"proxyConfiguration": {
    "type": "APPMESH",
    "containerName": "envoy",
    "properties": [
        {
            "name": "ProxyIngressPort",
            "value": "15000"
        },
        {
            "name": "AppPorts",
            "value": "5000"
        },
        {
            "name": "EgressIgnoredIPs",
            "value": "169.254.170.2,169.254.169.254"
        },
        {
            "name": "IgnoredUID",
            "value": "1337"
        },
        {
            "name": "ProxyEgressPort",
            "value": "15001"
        }
    ]
},

Definición de la tarea para el Virtual Gateway:

  • Configuramos un solo contenedor en esta tarea envoy-proxy.
  • No debemos configurar el proxyConfiguration.
  • Configuramos la variable APPMESH_RESOURCE_ARN con el nombre de nuestro Virtual Gateway
 "environment": [
	{
		"name": "APPMESH_RESOURCE_ARN",
		"value": "arn:aws:appmesh:eu-central-1:xxxxxxx:mesh/pxxx-local-appmesh/virtualGateway/pxxx-gateway"
	},
	{
		"name": "ENABLE_ENVOY_XRAY_TRACING",
		"value": "1"
	},
	{
		"name": "ENVOY_LOG_LEVEL",
		"value": "info"
	}

Luego de tener la definición de tarea del virtual Gateway y de los dos microservicios, creamos los servicios en ECS. El único servicio que tendrá exposición al ALB será el Virtual Gateway.

ms_python y ms_nodejs:

Virtual Gateway

Pruebas

Para realizar las pruebas, empleamos la herramienta Postman, donde configuramos nuestras solicitudes a los microservicios implementados en AWS.

  1. Realizamos una petición al microservicio de Python desde el balanceador de carga:

2. Realizamos una solicitud al microservicio de Python, incluyendo el nombre del servicio de Node.js como parámetro de entrada.

Conclusiones

En el transcurso de la demostración, se evidenció la efectiva comunicación entre los microservicios dentro de la malla que construye AWS App Mesh, utilizando el nombre del microservicio registrado en Cloud Map. Además, logramos exponerlos mediante el un Virtual Gateway que opera como un balanceador interno de AWS App Mesh. Esta configuración no solo facilita la interacción fluida entre servicios, sino que también demuestra la capacidad de AWS App Mesh para gestionar de manera eficiente el tráfico y la conectividad en un entorno de microservicios distribuidos.

Referencias

webinar AWS

Tags

Guía de posibilidades profesionales sobre AWS
He leído y acepto la política de privacidad
Acepto recibir emails sobre actividades de recruiting NTT DATA