APIs y MicroServicios en Empresas Monolíticas — Distributed Tracing — Tracing Distribuido en Kubernetes #3

Al implementar Microservicios es necesario tener trazabilidad de las peticiones que se generan entre los microservicios, al tener n pequeños servicios, no se puede saber el flujo de un proceso o en momentos que necesitas “debugear” algun flujo, esto no podria realizarse si no se cubre este concepto. Tambien nos ayuda para encontrar puntos de cuellos de botella que se puedan solucionar al tener la trazabilidad de solicitudes.

Existen varias herramientas para llevar el tracing distribuido de solicitudes.

1.- OpenTracing ques un vendor neutral para poder instrumentar el código y poder enviar la trazabilidad a herramientas como Zipkin o Jaeger. Su implementación es para los principales lenguajes de programación.
2.- Service Mesh sin instrumentar el código es posible obtener la trazabilidad de los servicios que se invocan o que tienen dependencias a otros, esto mediante sidecars proxys, esta traza se puede enviar a Zipkin o Jaeger.

Tomaremos la opción 2, considerando de que al tener n microservicios instrumentar cada uno sería una labor y pueda haber errores en su configuración e implementación.

Primeramente:

1.- Para realizar esta ambientación es necesario bajar los proyectos de clientes y creditos de las siguientes url’s.

https://github.com/jovaniac/api-creditos-microservicios-tracing.git

https://github.com/jovaniac/api-clientes-microservicios-tracing.git

Prerequisitos
1.- Tener un Cluster de Kubernetes, podemos instalar Minikube, en este caso se uso GKE como cluster.

Creacmos en cluster básico en Google Cloud Plattform:

4 Nodos workers, 2vCPU por Nodo
Cluster de Kubernetes como GKE

El cluster de Kubernetes se aproviciona rápidisimo!!

Cluster creado correctamente

Obtenemos los datos de conexión al cluster para Kubectl, con gcloud, es necesario tener instalado y configurado.

> gcloud container clusters get-credentials standard-cluster-6 --zone us-central1-a --project api-project-47298316825

Validamos que kubectl en nuestra maquina local, ya esta configurado con los datos en el archivo .config el cual apunta a nuestro cluster previamente creado, para esto obtendremos los datos con la siguiente instruccion de gcloud.

Validamos el cluster con:

> kubectl cluster-info
Nos asigna una IP en este caso 35.239.18.104

2.- Instalar Istio como Service Mesh

Instalación Istio

  1. - Istio es una plataforma abierta para conectar, administrar y asegurar microservicios, es necesario bajar los binarios de Istio de la siguiente dirección : https://github.com/istio/istio/releases

Descarga de Istio

> curl -L https://git.io/getLatestIstio | sh -

Nos direeccionamos dentro de la carpeta istio-1.0.5

> cd istio-1.0.5

Y configuramos el directorio para que pueda encontrar a Istioctl

> export PATH=$PWD/bin:$PATH

Antes de instalar los archivos manifiestos de Istio, daremos permisos de administrador de clúster (administrador) al usuario actual. Para crear las reglas RBAC necesarias para Istio, el usuario actual requiere permisos de administrador.

> kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)

Ahoraaaaaa si, a instalar ISTIO!!!, pero antes veremos que PODS, estan actualmente corriendo en nuestro Cluster.

Podemos visualizar que solo están corriendo los PODs que definen el funcionamiento del Cluster de Kubernetes, en otro artículo, hablaremos más a detalle de esos componentes.

Nos situamos en donde tenelos los binarios de Istio

> cd istio-1.0.5

Ejecutamos:

> kubectl apply -f install/kubernetes/istio-demo-auth.yaml
instalacion de componentes de Istio

Se comienzan a crear los PODs para Istio utiliza para su funcionamiento

> kubectl get pods,svc --all-namespaces

Validamos su instalación correctamente con la siguiente instrucción, ohteniendo todos los servicios creamos en el namespaces istio-system:

> kubectl get svc -n istio-system

Configuración de Istio

Habilitamos la Inyección para el namespace default, todo lo que se deploye en este namespace, automaticamente tendra un sidecar de Istio, Lo hacemos aplicando una etiqueta:

> kubectl label namespace default istio-injection=enabled

Validamos el inyector habilitado para el namespace default

> kubectl get namespace -L istio-injection

Antes de realizar el deploy de los 2 microservicios, es necesario genera los siguientes manifiestos:

  1. - istio-gateway.yml como Control Ingress Traffic

Control Ingress Traffic

En un entorno de Kubernetes, el recurso de ingreso de Kubernetes se utiliza para especificar los servicios que deben estar expuestos fuera del clúster. En una malla de servicios de Istio, un mejor enfoque (que también funciona tanto en Kubernetes como en otros entornos) es utilizar un modelo de configuración diferente, a saber, Istio Gateway.

Una puerta de enlace permite que las funciones de Istio, como el monitoreo y las reglas de ruta, se apliquen al tráfico que ingresa al clúster.

Las nuevas versiones de istio, dejaron atras el uso de Ingress, y ahora debemos configurar el siguiente Gateway para manejar el punto de entrada para nuestras solicitudes y estás redireccionarlas al ingressgateway

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

2.- microservicios-virtualservices.yml, Aqui se configuran las rutas para el tráfico que ingresa a través del Gateway:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: microservicios-gateway-vs
spec:
hosts:
- "*"
gateways:
- istio-gateway
http:
- match:
- uri:
prefix: /api/v1/clientes
route:
- destination:
host: servicio-cliente
- match:
- uri:
prefix: /api/v1/creditos
route:
- destination:
host: servicio-creditos

los host, serán nuestros services, para redirigir el tráfico.

Instalación de componentes:

> kubectl apply -f istio-gateway.yml
> kubectl apply -f microservicios-virtualservices.yml

Deploy y Services de MicroServicios
 Es necesario crear los archivos de deploy y service para nuestro microservicios de clientes y créditos, estos se deberán de ejecutar con kubectl en Kubernetes.

> kubectl apply -f kubernetes/

Deploy y Service de Clientes

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: servicio-cliente
labels:
app: servicio-cliente
spec:
selector:
matchLabels:
app: servicio-cliente
template:
metadata:
labels:
app: servicio-cliente
spec:
containers:
— name: servicio-cliente
image: jovaniac/servicio-cliente:0.0.1-snapshot
ports:
— containerPort: 8081
protocol: TCP

La imagen que se expresa en el Deploy de Cliente en este caso se publico en el registry de DockerHub.

Para poder crear la imagen, se creo el siguiente Dockerfile.

FROM openjdk:8u151-jre-slim
MAINTAINER jovaniac@gmail.com
COPY servicio-cliente.jar /opt/servicio-cliente.jar
EXPOSE 8081
ENTRYPOINT [“java”, “-Djava.awt.headless=true”, “-Xms256m”, “-Xmx256m”, “-jar”, “/opt/servicio-cliente.jar”]

Service Discovery de Clientes, importante no definir como LoadBalancer los services, ya que queremos que la comunicación sea por el ingresgateway de Istio.

apiVersion: v1
kind: Service
metadata:
name: servicio-cliente
labels:
app: servicio-cliente
spec:
ports:
- port: 8081
name: http
selector:
app: servicio-cliente

Nos ponemos en la raiz del proyecto de clientes y ejecutamos la siguiente instrucción, la cual nos servirá para poder instalar el microservicio en Kubernetes

> kubectl apply -f kubernetes/

Muy importante, podemos ver que en la columna de READY, nos indica 2/2 lo cual señala que se deployo 1 container sidecar y otro container con el microservicio de clientes.

Deploy de Cŕeditos:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: servicio-creditos
labels:
app: servicio-creditos
spec:
selector:
matchLabels:
app: servicio-creditos
template:
metadata:
labels:
app: servicio-creditos
spec:
containers:
— name: servicio-creditos
image: jovaniac/servicio-creditos:0.0.1-snapshot
ports:
— containerPort: 8081
protocol: TCP

La imagen que se expresa en el Deploy de Cliente en este caso se publico en el registry de DockerHub.

Para poder crear la imagen, se creo el siguiente Dockerfile.

FROM openjdk:8u151-jre-slim
MAINTAINER jovaniac@gmail.com
COPY servicio-creditos.jar /opt/servicio-creditos.jar
EXPOSE 8081
ENTRYPOINT ["java", "-Djava.awt.headless=true", "-Xms256m", "-Xmx256m", "-jar", "/opt/servicio-creditos.jar"]

Service Discovery de Créditos

apiVersion: v1
kind: Service
metadata:
name: servicio-creditos
labels:
app: servicio-creditos
spec:
ports:
- port: 8081
name: http
selector:
app: servicio-creditos

Nos ponemos en la raiz del proyecto de créditos y ejecutamos la siguiente instrucción, la cual nos servirá para poder instalar la aplicación en Kubernetes

> kubectl apply -f kubernetes/

Muy importante, podemos ver que en la columna de READY, nos indica 2/2 lo cual señala que se deployo 1 container sidecar y otro container con el microservicio de créditos.

Ejecución y Visualización

Obtenemos los datos del ingressgateway de Istio, para saber ip y puerto de acceso:

> kubectl get svc istio-ingressgateway -n istio-system

istio-system service/istio-ingressgateway LoadBalancer 10.15.250.106 146.148.44.109 80:31380/TCP,443:31390/TCP,31400:31400/TCP

Podemos ver el pueto 80 mapeado al exterior por el 31380 y modo seguro 31390.

Request a clientes:

> http://146.148.44.109:31380/api/v1/clientes

Payload de entrada:

{
“apellidoMaterno”: “cabrera”,
“apellidoPaterno”: “arzate”,
“direccion”: “test”,
“edad”: 29,
“email”: “jovaniac@gmail.com”,
“genero”: “h”,
“nombre”: “jovani”
}

Request con postman:

Respuesta, vemos que genera un folio de creación del cliente.

{
“folioCliente”: “-193107644”,
“nombre”: “jovani”,
“apellidoPaterno”: “arzate”,
“apellidoMaterno”: “cabrera”,
“email”: “jovaniac@gmail.com”,
“direccion”: “test”,
“genero”: “h”,
“edad”: 29
}

Log del Container, en Kubernetes, vemo como aparecen 2 peticiones que hemos realizado al microservicio de clientes construido con Spring Boot

> kubectl logs -f servicio-cliente-6489c6674c-nv6qt -n default servicio-cliente

Request al microservicio de Clientes, este a su vez invoca el microservicio de Créditos.

{
"montoCredito": "4500",
"folioCliente":"1431734275"
}

http://146.148.44.109:31380/api/v1/clientes/1431734275/creditos

Respuesta, vemos que se genera un folio folioCredito este es un identificador del crédito que crea el microservicio de créditos.

{
"folioCredito": "-1889995241",
"montoDeuda": 4500,
"folioCliente": "1431734275"
}

Podemos hacer algunas pruebas al microservicio de Créditos para poder ver su funcionamiento, invocando directamente la creación de créditos.

El Service Discovery que provee Kubernetes se basa en etiquetas y no es necesario aprovicionar de código o librerias a nuestros microservicios, esto es mucho mejor y podemos tener microservicios poliglotas en tipo de runtime, llamándose entre sí sin ser del mismo lenguaje.

AJaaa, y el tracing distribuido apa????

Jaeger es un sistema de rastreo distribuido. Ayuda a recopilar los datos de sincronización necesarios para solucionar problemas de latencia en arquitecturas de microservicio. Gestiona tanto la recopilación como la búsqueda de estos datos. Istio recopilará las trazas de seguimiento.

Configuraremos el acceso al panel de control de Jaeger mediante el reenvío de puertos:

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

Ahora accedemos a

http://localhost:16686/search

En la parte de Service, nos aparecerán todas las aplicaciones las cuales generan tráfico http y pasan por el sidecar de Istio, el cual será el encargado de enviarlas a Jaeger, tenemos diferentes filtros que podemos utilizar para las busquedas del tracing que necesitemos observar.

Seleccionamos el microservicio de Clientes y le damos en Find Traces.

Nos aparece toda la información de las solicitues que se han realizado a travéz del tiempo, así como cado uno de los request realizados.

Pero eso no es todo podemos ver más detalle.

Podemos ver la trazabilidad entre microservicios, osea que MICROSERVICIO invoca a OTROS MICROSERVICIOS, y así sucesivamente tantas peticiones HTTP tengamos orquestadas!!!! a verdad!!!!!!!! un API Gateway queda fuera de este potencial que tenemos con Istio.

Podemos ver que la peticion llega por clientes, y fue asi, se solicito un crédito vía el microservicio de clientes, pero invoco a quien tenia la responsabilidad de crear los créditos, en este caso al microservicio de créditos. validar el código para su entendimiento.

Ahora tambien podemos ver las dependencias en las llamadas que se están realizan los microservicios. en el TAB de Dependencies en Jaeger podemos visualizar las solicitudes que ha tenido y el flujo de invocación.

Depencias de clientes
Dependencias de créditos

Ahora tambien, podremos ver algunos datos de los diferentes request que se ejecutaron.

Voy a cerrar con el siguiente tema a revisar que será, métricas centralizadas, para esto Istio tambien será nuestro aliado.

Te invito a que leas el overview de microservicios en el siguiente Link.

y mi artículo del Patron Service Discovery en Kubernetes.

Jovani Arzate | apificación | microservicios | kubernetes | service discovery | apis | spring boot | microservices | distributed tracing | tracing distribuido