APIs y MicroServicios en Empresas Monolíticas — Service Discovery en Kubernetes #2

En este artículo hablaremos del patron de Service Discovery que debemos considerar al implementar Microservicios en Kubernetes, ya que necesitamos de un mecanismo para poder descubrir y registrar las aplicaciones y poder acceder a ellas en un momento inicial, con una instancia y cuando se produzca scaling de la aplicación al tener más demanda.

Un Service de Kubernetes es un componente que permite una politíca para definir la forma en la cual se puede acceder a un pod.

Descubrir los containers y no la aplicación.

Es por ello que nuestros MicroServicios pueden estár en cualquier lenguaje de programacion al usar contenedores.

• El kube-proxy implementa IPs virtuales para los Services.
• Para acceder a la instancias particulares de los contenedores se usa el Service Discovery de Kubernetes.
– Variables de ambiente:
• {SVCNAME}_SERVICE_HOST
• {SVCNAME}_SERVICE_PORT
– DNS Interno: Método recomendado
• El kube-proxy hará el balanceo entre las distintas instancias.

Pero…. bueno eso es teoría show me the code:

1.- Para realizar la implementacion es necesario bajar los proyectos de clientes y creditos que se encuentran alojados en github, dos simples microservicios que se comunican entre sí y que accederemos a ellos vía el discovery de Kubernetes.

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

microk8s.kubectl cluster-info
Información del Cluster
microk8s.kubectl get nodes
Nodos del cluster

2.- Bajar el código de los repositorios (cliente, creditos).

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

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

kind: Service
apiVersion: v1
metadata:
name: servicio-cliente
spec:
type: LoadBalancer
selector:
app: servicio-cliente
ports:
— protocol: TCP
port: 8081
targetPort: 8081

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

microk8s.kubectl apply -f kubernetes/
Se instala el microservicio Clientes

Muy importante lo siguiente ya que es la forma en que Kubernetes descubre un deploy previamente creado, por default al crear un deploy que genera una POD, este no es accesible desde ningun lugar, pero vía un Service (que implementa el servicio de descubrimiento) es la forma de acceder a los diferentes servicios que se encuentran en los PODS en el containers creado.

kind: Service
 selector:
 #etiqueta para buscar el pod dentro de kubernetes
 app: servicio-cliente
microk8s.kubectl get pods,svc --all-namespaces
servicios de ambos microservicios

Podemos ver que ya se encuentra corriendo el POD de servicio-cliente, así mismo el service que para esta demostración es el importante, ya que será la forma en que nosotros podamos descubrir al deployment previamente creado, sin este SERVICE, no habría forma de acceder al POD.

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

kind: Service
apiVersion: v1
metadata:
name: servicio-creditos
spec:
type: LoadBalancer
selector:
app: servicio-creditos
ports:
— protocol: TCP
port: 8081
targetPort: 8081

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

microk8s.kubectl apply -f kubernetes/
Instalacion de microservicio créditos

Configuración de Cliente Feign
En este caso estamos usando Feign es una libreria la cual nos permite crear clientes de manera sencilla para la invocación de servicios.

Muy importante que se mapea con el nombre del service y el puerto que se expone del container, en este caso invocaremos desde el Microservicio de Clientes el microservicio de Creditos, esto para simular la invocacion del servicio remoto, recordemos que los microservicios se invocan entre si, ya que cada api debe contener su responsabilidad unica para lo cual fue creado.

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import com.bancoazteca.clienteunico.clientes.service.creditos.modelo.Credito;
import com.bancoazteca.clienteunico.clientes.service.creditos.modelo.ResumenCredito;
@FeignClient(name = “servicio-creditos”, url = “http://servicio-creditos:8081")
public interface CreditosServiceRemoteClient {
@RequestMapping(method = POST, value = “api/v1/creditos”)
ResumenCredito guardarCredito(@RequestBody Credito credito);
}

url = “http://servicio-creditos:8081", etiqueta para encontrar el pod servicio-creditos.

Ejecución 
1.- El puerto 31346 usado en el request es del servicio de cliente, este te lo provee automaticamente Kubernetes, puedes consultar los puertos con (esto solo para microk8s o minikube ya que en un ambiente productivo usaremos un unico punto de acceso con un API GATEWAY como Apigee de Google o el Ingress que provea un proxy o un Service Mesh, así mismo la configuracion de IP deberá cambiar y NO usar LoadBalancer por cada microservicio):

microk8s.kubectl get services
servicios de descubrimiento, Kubernetes les asocia un puerto random

Request al microservicio de clientes con postman, para la creación de un cliente.

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

http:localhost:31346/api/v1/clientes

request y response del microservicio clientes

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

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

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

{
“montoCredito”: “4500”,
“folioCliente”:”346538239"
}

localhost:31346/api/v1/clientes/346538239/creditos

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

{
“folioCredito”: “104549553”,
“montoDeuda”: 4500,
“folioCliente”: “346538239”
}
request y response del microservicio clientes, creando un crédito

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.

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

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