Volver a los microservicios con Istio. Parte 1



Nota perev. : Las mallas de servicio se han convertido definitivamente en una solución relevante en la infraestructura moderna para aplicaciones que siguen la arquitectura del microservicio. Aunque Istio puede ser escuchado por muchos ingenieros de DevOps, es un producto bastante nuevo que, al ser exhaustivo en términos de las características proporcionadas, puede requerir un tiempo considerable para conocerse. El ingeniero alemán Rinor Maloku, responsable de la informática en la nube para grandes clientes de la empresa de telecomunicaciones Orange Networks, ha escrito una maravillosa serie de materiales que le permiten sumergirse rápida y profundamente en Istio. Comienza su historia con lo que Istio puede hacer y cómo puede verlo rápidamente con sus propios ojos.

Istio es un proyecto de código abierto desarrollado en colaboración con equipos de Google, IBM y Lyft. Resuelve las dificultades que surgen en aplicaciones basadas en microservicios, por ejemplo, tales como:

  • Gestión del tráfico : tiempos de espera, reintentos, equilibrio de carga;
  • Seguridad : autenticación y autorización del usuario final;
  • Observabilidad : rastreo, monitoreo, registro.

Todos ellos pueden resolverse a nivel de aplicación, pero después de eso, sus servicios dejarán de ser "micro". Todos los esfuerzos adicionales para resolver estos problemas son un desperdicio adicional de recursos de la compañía que podrían usarse directamente para los valores comerciales. Considere un ejemplo:
Gerente de proyecto: ¿Cuánto tiempo para agregar comentarios?
Desarrollador: Dos sprints.

MP: ¿Qué? ¡Es CRUDO!
R: Hacer CRUD es una parte simple de la tarea, pero aún necesitamos autenticar y autorizar usuarios y servicios. Dado que la red no es confiable, deberá implementar solicitudes repetidas, así como el patrón de disyuntor en los clientes. Aún así, para asegurarse de que todo el sistema no se caiga, necesitará tiempos de espera y mamparos (para obtener más detalles sobre los dos patrones mencionados, consulte más adelante en el artículo - Transl. Aprox.) , Y para detectar problemas, monitoreo, rastreo, [...]

MP: Oh, entonces simplemente insertemos esta función en el servicio del Producto.
Creo que la idea es clara: el volumen de pasos y esfuerzos necesarios para agregar un servicio es enorme. En este artículo, veremos cómo Istio elimina todas las dificultades mencionadas anteriormente (que no están dirigidas a la lógica empresarial) de los servicios.



Nota : Este artículo asume que tienes conocimiento práctico de Kubernetes. De lo contrario, recomiendo leer mi introducción a Kubernetes y solo después de eso continúe leyendo este material.

Idea Istio


En un mundo sin Istio, un servicio realiza solicitudes directas a otro, y en caso de falla, el servicio debe procesarlo por sí mismo: hacer un nuevo intento, proporcionar un tiempo de espera, abrir un interruptor de circuito, etc.


Tráfico de red en Kubernetes

Istio también ofrece una solución especializada, completamente separada de los servicios y el funcionamiento al interferir con la interacción de la red. Y así implementa:

  • Tolerancia a fallas : según el código de estado en la respuesta, comprende si la solicitud ha fallado y la ejecuta nuevamente.
  • Lanzamientos de Canarias : redirige a la nueva versión del servicio solo un porcentaje fijo del número de solicitudes.
  • Monitoreo y métricas : ¿cuánto tiempo respondió el servicio?
  • Seguimiento y observabilidad : agrega encabezados especiales a cada solicitud y los rastrea en el clúster.
  • Seguridad : extrae el token JWT, autentica y autoriza a los usuarios.

Estas son solo algunas de las posibilidades (¡realmente solo unas pocas!) Para intrigarlo. ¡Ahora profundicemos en los detalles técnicos!

Arquitectura Istio


Istio intercepta todo el tráfico de red y le aplica un conjunto de reglas, insertando un proxy inteligente en cada pod en forma de contenedor de sidecar. Los proxies que activan todas las funciones forman un plano de datos y pueden configurarse dinámicamente usando el plano de control .

Plano de datos


Los proxies insertados en los pods le permiten a Istio cumplir fácilmente los requisitos que necesitamos. Por ejemplo, verifique las funciones de reintento y disyuntor.


Cómo se implementan los reintentos y la interrupción de circuito en Envoy

Para resumir:

  1. Enviado (hablando de un proxy en un contenedor de sidecar que se distribuye como un producto separado , aprox. Transl.) Envía una solicitud a la primera instancia del servicio B y se produce un error.
  2. Enviado Reintentos de sidecar. (1)
  3. La solicitud fallida se devuelve al proxy que la llamó.
  4. Esto abre el disyuntor y llama al siguiente servicio para solicitudes posteriores. (2)

Esto significa que no tiene que usar la próxima biblioteca Retry, no tiene que hacer su propia implementación de Circuit Breaking and Service Discovery en el lenguaje de programación X, Y o Z. Todo esto y mucho más está disponible de forma inmediata en Istio y no requiere ningún cambio en el código.

Genial Ahora es posible que desee hacer un viaje con Istio, pero todavía hay algunas dudas, preguntas abiertas. Si esta es una solución universal para todos los casos en la vida, entonces tiene una sospecha legítima: después de todo, todas esas decisiones en realidad resultan inadecuadas para cualquier caso.

Y finalmente, preguntas: "¿Es personalizable?"

Ahora está listo para un viaje por mar, y conozcamos el plano de control.

Plano de control


Consta de tres componentes: Piloto , Mezclador y Ciudadela , que trabajan juntos para configurar Enviados para enrutar el tráfico, aplicar políticas y recopilar datos de telemetría. Esquemáticamente, todo se ve así:


Control de la interacción del plano con el plano de datos

Los enviados (es decir, el plano de datos) se configuran utilizando Kubernetes CRD (Definiciones de recursos personalizados) definidos por Istio y diseñados específicamente para este propósito. Para usted, esto significa que parecen ser el próximo recurso en Kubernetes con sintaxis familiar. Después de la creación, este recurso será recogido por el plano de control y aplicado a los Enviados.

Relación de servicio para Istio


Describimos la actitud de Istio hacia los servicios, pero no lo contrario: ¿cómo se relacionan los servicios con Istio?

Honestamente, Istio sabe acerca de la presencia de servicios y peces, sobre el agua, cuando se preguntan: "¿Qué es el agua en general?".


Ilustración de Victoria Dimitrakopoulos : - ¿Qué le parece el agua? - ¿Qué es el agua en general?

Por lo tanto, puede tomar el clúster de trabajo y después de la implementación de los componentes de Istio, los servicios ubicados en él continuarán funcionando, y después de la eliminación de estos componentes, todo estará bien nuevamente. Está claro que al hacerlo, perderá las oportunidades que brinda Istio.

Suficiente teoría: ¡pongamos este conocimiento en práctica!

Istio en la práctica


Istio requiere un clúster de Kubernetes en el que estén disponibles al menos 4 vCPU y 8 GB de RAM. Para elevar rápidamente el clúster y seguir las instrucciones del artículo, recomiendo usar Google Cloud Platform, que ofrece a los nuevos usuarios $ 300 gratis .

Después de crear un clúster y configurar el acceso a Kubernetes a través de la utilidad de la consola, puede instalar Istio a través del administrador de paquetes Helm.

Instalación de timón


Instale el cliente Helm en su computadora, como dicen en la documentación oficial . Lo usaremos para generar plantillas para instalar Istio en la siguiente sección.

Instalar Istio


Descargue los recursos de Istio de la última versión (el enlace del autor original a la versión 1.0.5 se cambia al actual, es decir, 1.0.6 - aprox. Transl.) , Extraiga el contenido en un directorio, que llamaré en el futuro [istio-resources] .

Para facilitar la identificación de los recursos de Istio, cree el espacio de nombres del istio-system istio en el clúster K8s:

 $ kubectl create namespace istio-system 

Complete la instalación yendo al [istio-resources] y ejecutando el comando:

 $ helm template install/kubernetes/helm/istio \ --set global.mtls.enabled=false \ --set tracing.enabled=true \ --set kiali.enabled=true \ --set grafana.enabled=true \ --namespace istio-system > istio.yaml 

Este comando mostrará los componentes clave de Istio en el archivo istio.yaml . Cambiamos la plantilla estándar para nosotros, especificando los siguientes parámetros:

  • global.mtls.enabled establece en false (es decir, la autenticación mTLS está deshabilitada, aprox. transl.) para simplificar nuestro proceso de citas;
  • tracing.enabled habilita el rastreo de consultas usando Jaeger;
  • kiali.enabled instala Kiali en un clúster para visualizar servicios y tráfico;
  • grafana.enabled configura Grafana para visualizar las métricas recopiladas.

Aplicamos los recursos generados con el comando:

 $ kubectl apply -f istio.yaml 

¡La instalación de Istio en el clúster ha finalizado! Espere hasta que todos los pods en el istio-system nombres del istio-system estén en Running o Completed ejecutando el siguiente comando:

 $ kubectl get pods -n istio-system 

Ahora estamos listos para continuar en la siguiente sección, donde abordaremos y lanzaremos la aplicación.

Arquitectura de aplicaciones de análisis de sentimientos


Tomemos un ejemplo de la aplicación de microservicio Sentiment Analysis utilizada en el artículo de introducción ya mencionado en Kubernetes . Es lo suficientemente sofisticado como para mostrar las capacidades de Istio en la práctica.

La aplicación consta de cuatro microservicios:

  1. Servicio SA-Frontend , que sirve aplicaciones front-end en Reactjs;
  2. Un servicio SA-WebApp que atiende solicitudes de análisis de opinión;
  3. Servicio SA-Logic , que realiza análisis sentimentales ;
  4. Servicio SA-Feedback , que recibe comentarios de los usuarios sobre la precisión del análisis.



En este diagrama, además de los servicios, también vemos el controlador de ingreso, que en Kubernetes enruta las solicitudes entrantes a los servicios correspondientes. Istio utiliza un concepto similar dentro de Ingress Gateway, cuyos detalles seguirán a continuación.

Lanzar una aplicación con un proxy desde Istio


Para las operaciones adicionales mencionadas en el artículo, clone el repositorio de istio-dominio . Contiene la aplicación y los manifiestos para Kubernetes e Istio.

Insertar sidecar


La inserción se puede hacer de forma automática o manual . Para insertar automáticamente contenedores de sidecar, debe establecer la istio-injection=enabled en el istio-injection=enabled , que se realiza mediante el siguiente comando:

 $ kubectl label namespace default istio-injection=enabled namespace/default labeled 

Ahora cada pod que se desplegará en el espacio de nombres predeterminado recibirá su contenedor de sidecar. Para verificar esto, [istio-mastery] una aplicación de prueba yendo al directorio raíz del [istio-mastery] y ejecutando el siguiente comando:

 $ kubectl apply -f resource-manifests/kube persistentvolumeclaim/sqlite-pvc created deployment.extensions/sa-feedback created service/sa-feedback created deployment.extensions/sa-frontend created service/sa-frontend created deployment.extensions/sa-logic created service/sa-logic created deployment.extensions/sa-web-app created service/sa-web-app created 

Después de expandir los servicios, verificaremos que los pods tengan dos contenedores (con el servicio en sí y su sidecar), ejecutando el kubectl get pods y asegurándonos de que el valor 2/2 indique en la columna READY , lo que simboliza que ambos contenedores se están ejecutando:

 $ kubectl get pods NAME READY STATUS RESTARTS AGE sa-feedback-55f5dc4d9c-c9wfv 2/2 Running 0 12m sa-frontend-558f8986-hhkj9 2/2 Running 0 12m sa-logic-568498cb4d-2sjwj 2/2 Running 0 12m sa-logic-568498cb4d-p4f8c 2/2 Running 0 12m sa-web-app-599cf47c7c-s7cvd 2/2 Running 0 12m 

Visualmente se ve así:


Enviado proxy en una de las vainas

Ahora que la aplicación está en funcionamiento, debemos permitir que el tráfico entrante ingrese a la aplicación.

Puerta de entrada


La mejor práctica para lograr esto (para permitir el tráfico en el clúster) es a través de Ingress Gateway en Istio, que se encuentra en el "borde" del clúster y le permite habilitar las funciones de Istio como enrutamiento, equilibrio de carga, seguridad y monitoreo del tráfico entrante.

El componente Ingress Gateway y el servicio que lo reenvía al exterior se instalaron en el clúster durante la instalación de Istio. Para averiguar la dirección IP externa de un servicio, haga lo siguiente:

 $ kubectl get svc -n istio-system -l istio=ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP istio-ingressgateway LoadBalancer 10.0.132.127 13.93.30.120 

Continuaremos accediendo a la aplicación a través de esta IP (me referiré a ella como IP EXTERNA), por lo que, por conveniencia, escribiremos el valor en una variable:

 $ EXTERNAL_IP=$(kubectl get svc -n istio-system \ -l app=istio-ingressgateway \ -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') 

Si intenta acceder a esta IP a través de un navegador ahora, recibirá un error de Servicio no disponible, porque Por defecto, Istio bloquea todo el tráfico entrante hasta que se define una puerta de enlace.

Recurso de puerta de enlace


Gateway es un CRD (Definición de recursos personalizados) en Kubernetes, definido después de instalar Istio en un clúster y activar la capacidad de especificar los puertos, protocolos y hosts para los que queremos permitir el tráfico entrante.

En nuestro caso, queremos permitir el tráfico HTTP al puerto 80 para todos los hosts. La tarea se implementa mediante la siguiente definición ( http-gateway.yaml ) :

 apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: http-gateway spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" 

Esta configuración no necesita explicación, excepto el istio: ingressgateway . Con este selector, podemos indicar a qué Ingress Gateway se aplica la configuración. En nuestro caso, este es el controlador Ingress Gateway, que se instaló por defecto en Istio.

La configuración se aplica llamando al siguiente comando:

 $ kubectl apply -f resource-manifests/istio/http-gateway.yaml gateway.networking.istio.io/http-gateway created 

Ahora la puerta de enlace permite el acceso al puerto 80, pero no tiene idea de dónde enrutar las solicitudes. Esto requerirá servicios virtuales .

Recurso VirtualService


VirtualService le dice a Ingress Gateway cómo enrutar las solicitudes que están permitidas dentro del clúster.

Las solicitudes a nuestra aplicación que se envían a través de http-gateway deben enviarse a los servicios sa-frontend, sa-web-app y sa-feedback:


Rutas para configurar con VirtualServices

Considere las solicitudes que deben enviarse a SA-Frontend:

  • Se debe enviar una coincidencia exacta en / path a SA-Frontend para obtener index.html;
  • Las rutas con el prefijo /static/* deben enviarse a SA-Frontend para recibir archivos estáticos utilizados en la interfaz, como CSS y JavaScript;
  • Las rutas que coinciden con la expresión regular '^.*\.(ico|png|jpg)$' deben enviarse a SA-Frontend, como Estas son las imágenes que se muestran en la página.

La implementación se logra mediante la siguiente configuración ( sa-virtualservice-external.yaml ):

 kind: VirtualService metadata: name: sa-external-services spec: hosts: - "*" gateways: - http-gateway # 1 http: - match: - uri: exact: / - uri: exact: /callback - uri: prefix: /static - uri: regex: '^.*\.(ico|png|jpg)$' route: - destination: host: sa-frontend # 2 port: number: 80 

Puntos importantes:

  1. Este servicio virtual se refiere a las solicitudes que llegan a través de http-gateway ;
  2. destination define el servicio donde se envían las solicitudes.

Nota : La configuración anterior se almacena en el archivo sa-virtualservice-external.yaml , que también contiene la configuración para el enrutamiento en SA-WebApp y SA-Feedback, pero se acortó aquí en el artículo para mayor brevedad.

Aplique VirtualService llamando a:

 $ kubectl apply -f resource-manifests/istio/sa-virtualservice-external.yaml virtualservice.networking.istio.io/sa-external-services created 

Nota : Cuando usamos los recursos de Istio, el Servidor API de Kubernetes genera un evento que recibe el Plano de control de Istio, y después de eso, la nueva configuración se aplica a los proxies Envoy de cada pod. Y el controlador de Ingress Gateway parece ser el próximo Envoy configurado en Control Plane. Todo esto en el diagrama se ve así:


Configuración de Istio-IngressGateway para enrutamiento de consultas

El Análisis de sentimientos se ha hecho disponible en http://{EXTERNAL-IP}/ . No se preocupe si obtiene el estado No encontrado: a veces la configuración tarda un poco más y la caché de Envoy se actualiza .

Antes de continuar, trabaje un poco con la aplicación para generar tráfico (su presencia es necesaria para mayor claridad en los próximos pasos: aprox. Transl.) .

Kiali: Observabilidad


Para acceder a la interfaz administrativa de Kiali, ejecute el siguiente comando:

 $ kubectl port-forward \ $(kubectl get pod -n istio-system -l app=kiali \ -o jsonpath='{.items[0].metadata.name}') \ -n istio-system 20001 

... y abra http: // localhost: 20001 / , iniciando sesión como admin / admin. Aquí encontrará muchas funciones útiles, por ejemplo, para verificar la configuración de los componentes de Istio, visualizar servicios basados ​​en la información recopilada al interceptar solicitudes de red y recibir respuestas a las preguntas "¿Quién se comunica con quién?", "¿Qué versión del servicio tiene fallas?" etc. En general, explore las posibilidades de Kiali antes de pasar a visualizar métricas con Grafana.



Grafana: visualización de métricas


Las métricas recopiladas en Istio entran en Prometheus y se visualizan con Grafana. Para ingresar a la interfaz de administración de Grafana, ejecute el siguiente comando, luego abra http: // localhost: 3000 / :

 $ kubectl -n istio-system port-forward \ $(kubectl -n istio-system get pod -l app=grafana \ -o jsonpath={.items[0].metadata.name}) 3000 

Al hacer clic en el menú Inicio en la esquina superior izquierda y seleccionar Istio Service Dashboard en la esquina superior izquierda, comience con el servicio sa-web-app para ver las métricas recopiladas:



Aquí estamos esperando un rendimiento vacío y completamente aburrido; la administración nunca lo aprobará. Creemos una pequeña carga con el siguiente comando:

 $ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done 

Ahora tenemos gráficos mucho mejores y, además de ellos, maravillosas herramientas de Prometheus para monitorear y Grafana para visualizar métricas, lo que nos permitirá conocer el rendimiento, el estado de salud, las mejoras / degradación de los servicios a lo largo del tiempo.

Finalmente, veamos el rastro de solicitudes en los servicios.

Jaeger: rastro


Necesitaremos seguimiento, porque cuantos más servicios tengamos, más difícil será llegar a la causa de la falla. Veamos un caso simple de la imagen a continuación:


Un ejemplo típico de una solicitud fallida aleatoria

La solicitud llega, cae, ¿cuál es el motivo? Primer servicio? O el segundo? Hay excepciones en ambos: echemos un vistazo a los registros de cada uno. ¿Con qué frecuencia te encuentras haciendo esto? Nuestro trabajo se parece más a los detectives de software que a los desarrolladores ...

Este es un problema generalizado en microservicios y se resuelve mediante sistemas de rastreo distribuidos en los que los servicios se pasan entre sí un encabezado único, después de lo cual esta información se redirige al sistema de rastreo, donde se asigna a los datos de la solicitud. Aquí hay una ilustración:


TraceId se utiliza para identificar la solicitud.

Istio utiliza Jaeger Tracer, que implementa un marco de API OpenTracing independiente del proveedor. Puede acceder a la interfaz de usuario de Jaeger con el siguiente comando:

 $ kubectl port-forward -n istio-system \ $(kubectl get pod -n istio-system -l app=jaeger \ -o jsonpath='{.items[0].metadata.name}') 16686 

Ahora vaya a http: // localhost: 16686 / y seleccione el servicio sa-web-app . Si el servicio no se muestra en el menú desplegable, muestre / genere actividad en la página y actualice la interfaz. Después de eso, haga clic en el botón Buscar rastros , que mostrará los últimos rastros, seleccione cualquiera, aparecerá información detallada sobre todos los rastros:



Este rastro muestra:

  1. La solicitud llega a istio-ingressgateway (esta es la primera interacción con uno de los servicios, y se genera la identificación de seguimiento para la solicitud), después de lo cual la puerta de enlace envía la solicitud al servicio sa-web-app .
  2. En el servicio sa-web-app, la solicitud es recogida por el sidecar de Envoy, se crea un "hijo" en el lapso (por lo tanto, lo vemos en las trazas) y se redirige al contenedor de la aplicación sa-web . ( Span es una unidad lógica de trabajo en Jaeger que tiene un nombre, la hora en que comenzó la operación y su duración. Los tramos pueden anidarse y ordenarse. Un gráfico acíclico dirigido desde tramos forma una traza. - Transl. Aprox.)
  3. Aquí, la solicitud se procesa mediante el método sentimentAnalysis . La aplicación ya genera estos rastros, es decir requirieron cambios al código.
  4. A partir de este momento, se inicia una solicitud POST a sa-logic . La identificación de seguimiento debe reenviarse desde sa-web-app .
  5. ...

Nota : En el paso 4, la aplicación debería ver los encabezados generados por Istio y pasarlos a solicitudes posteriores, como se muestra en la imagen a continuación:


(A) Istio es responsable de reenviar los encabezados; (B) Los servicios son responsables de los encabezados.

Istio hace la mayor parte del trabajo, como genera encabezados para las solicitudes entrantes, crea nuevos tramos en cada atención lateral y los reenvía. Sin embargo, sin trabajar con los encabezados dentro de los servicios, se perderá la ruta de seguimiento completa de la solicitud.

Se deben considerar (reenviar) los siguientes encabezados:

 x-request-id x-b3-traceid x-b3-spanid x-b3-parentspanid x-b3-sampled x-b3-flags x-ot-span-context 

Sin embargo, esta es una tarea simple, para simplificar su implementación, ya existen muchas bibliotecas ; por ejemplo, en el servicio sa-web-app, el cliente RestTemplate reenvía estos encabezados si simplemente agrega las bibliotecas Jaeger y OpenTracing dependiendo de ello .

Tenga en cuenta que la aplicación Sentiment Analysis muestra implementaciones en Flask, Spring y ASP.NET Core.

Ahora que ha quedado claro lo que estamos sacando de la caja (o casi "fuera de la caja"), consideraremos cuestiones de enrutamiento finamente ajustado, gestión del tráfico de red, seguridad, etc.

Nota perev. : Lea sobre esto en la próxima entrega de Istio de Rinor Maloku, que estará disponible en nuestro blog en un futuro próximo. ACTUALIZACIÓN (14 de marzo): la segunda parte ya ha sido publicada.

PD del traductor


Lea también en nuestro blog:

Source: https://habr.com/ru/post/438426/


All Articles