Microservicios con Spring Cloud Kubernetes
Cuando decidimos construir una arquitectura basadas en microservicios hacer uso de Spring Cloud y Kubernetes como plataforma para desplegarlos, son unas buenas soluciones. Por lo que en este artículo Microservicios con Spring Cloud Kubernetes, vamos a explorar el proyecto, bastante reciente todavía de Pivotal Spring Cloud Kubernetes. Si necesitas una introducción a Kubernetes quizás estos artículos te vengan bien. Aunque haremos uso de otras piezas como MongoDb, circuit breaker o comunicación a través de WebClient, en este artículo nos centraremos en el despliegue y configuración en Kubernetes, y haremos mención al resto de funcionalidades creadas.
¿Qué necesitamos para empezar?
- Una instalación de Kubernetes, en nuestro caso usamos Minikube, configurada y arrancada.
- Dos aplicaciones Spring Boot que se podrán comunicar a través de REST.
De todos modos todo lo necesario lo puedes encontrar en nuestro github
¿Qué vamos a construir y a usar?
El ejemplo que hemos creado consiste en la comunicación de dos microservicios, una tienda la cual hace pedidos, un ejemplo muy simple y sencillo pero que trae los conceptos necesarios para sacar provecho de Kubernetes. Este hará uso de un Service Discovery y un Load Balancer proporcionados por Kubernetes y además usaremos Hystrix como circuit breaker habilitado un fallback por si hubiera algún error al realizar la llamada a otro microservicio usando WebClient..
En nuestro ejemplo vamos a usar
- Secretos (secrets): Los secretos de kubernetes nos permite almacenar información sensible como passwords, OAuth tokens, ssh keys etc…, en nuestro caso guardaremos la password y el usuario de la base de datos MongoDb.
- ConfigMaps: Es un objeto utilizado para almacenar datos no confidenciales ni sensibles, se almacenan en formato clave valor, en nuestro caso almacenará un texto para mostrar los servicios.
- Balanceador de Carga (Load balancer): En este caso se usará Ribbon para balancear la carga entre dos instancias.
- Servicio de descubrimiento (service discovery): La dependencia de Kubernetes de Spring Cloud nos ayudará a descubrir las instancias o servicios desplegados.
Ejemplo Kubernetes y Spring Cloud
Dependencias Maven
A continuación mostramos las dependencias de kubernetes necesarias para las aplicaciones:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes- ribbon</artifactId> </dependency>
A parte, se han añadido alguna dependencia más del stack de netflix así como la dependencia de mongo, y spring cloud versión Hoxton.SR8
Configuración del Service Discovery y Load Balancer
Para poder hacer uso del service discovery y del balanceador con Ribbon vamos a activarlo en la clase principal de la aplicación:
@RibbonClient(name = "order-service", configuration = RibbonConfiguration.class) @EnableDiscoveryClient
Con las anotaciones anteriores en la clase main del proyecto de Spring, hemos activado el balanceador de carga con Ribbon, para que pueda balancear las peticiones que haremos entre las instancias.
Configuración de ConfigMap y Secrets
En Spring Cloud podemos hacer uso del Config Server para guardar información no sensible y de Vault para guardar secretos o información sensible como Passwords. Pero con Spring Cloud Kubernetes podemos utilizar los objetos Secrets y ConfigMap de la propia plataforma de Kubernetes para este tipo de información.
ConfigMap
Para poder hacer uso del configmap de kubernetes primero habrá que desplegar un yaml de este tipo:
apiVersion: v1 kind: ConfigMap metadata: name: shop-service data: application.properties: |- configmap.message=Services : %s
Y a continuación para poder leer de este fichero la información ( de data), habrá que mapearlo con la aplicación:
@Configuration @ConfigurationProperties(prefix = "configmap") public class ShopConfig { private String message = "Services : %s";
de esta manera, seremos capaces de mostrar en el campo message el texto del configmap, hay que tener en cuenta el nombre del configmap debe coincidir con el del servicio para que sea accesible.
kubectl apply -f configmap.yaml
Secrets
Como hemos comentado los secrets en Kubernetes es un tipo de objeto en el que guardaremos información sensible como podríamos hacer en Vault con Spring.
Para poder crear objetos por ejemplo, en nuestro caso para la contraseña y el usuario de MongoDb, vamos a crear un objeto Secrets de la siguiente manera:
apiVersion: v1 kind: Secret metadata: name: db-secret data: username: dXNlcg== password: cDQ1NXcwcmQ=
Una vez que hemos desplegado este objeto podremos utilizar esta información donde sea necesaria.
kubectl apply -f secret.yaml
Uso de Secrets de Kubernetes
Una vez que hemos desplegado los secretos vamos a ver su uso mediante una imagen de MongoDb en kubernetes:
apiVersion: apps/v1 kind: Deployment metadata: name: mongo spec: replicas: 1 selector: matchLabels: service: mongo template: metadata: labels: service: mongo name: mongodb-service spec: containers: - args: - mongod image: mongo:latest name: mongo env: - name: MONGO_INITDB_ROOT_USERNAME valueFrom: secretKeyRef: name: db-secret key: username - name: MONGO_INITDB_ROOT_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password
kubectl create -f mongo-deployment.yaml
En el anterior objeto vamos a utilizar la clave y el usuario creados en el secreto, lo único que habrá que tener en cuenta que habrá que habrá que utilizar el mismo nombre que como se llama el secreto desplegado en nuestro caso es db-secret.
Configuración del Servicio para usar secretos
Una vez se ha desplegado tanto el objecto secrets como el deployment, que usará los secrets, en nuestro caso MongoDb, habrá que hacer configurar el application de la aplicación para que puedan ser aplicados:
spring: application: name: order-service cloud: kubernetes: reload: enabled: true secrets: name: db-secret data: mongodb: host: mongodb-service port: 27017 database: admin username: ${MONGO_USERNAME} password: ${MONGO_PASSWORD}
En este caso lo que le hemos dicho a nuestro servicio donde van a estar los secrets, y la clave y la contraseña no la escribimos.
Configuración de Acceso basado en Roles
Como último de paso de configuración, sin el cual, nuestras aplicaciones tal y como están no funcionarían, faltaría un acceso basado en roles dentro del clúster. De esta manera nos vamos a asegurar que un Pod que se ejecuta con spring-cloud-kubernets tenga acceso a la API de Kuberntes, y así por ejemplo en nuestro ejemplo pueda obtener todos los servicios.
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: namespace-reader rules: - apiGroups: ["", "extensions", "apps"] resources: ["configmaps", "pods", "services", "endpoints", "secrets"] verbs: ["get", "list", "watch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: namespace-reader-binding namespace: default subjects: - kind: ServiceAccount name: default apiGroup: "" roleRef: kind: Role name: namespace-reader apiGroup: ""
Desplegar aplicación Spring Cloud en Kubernetes
Una vez que hemos creado todos nuestro objetos de kubernetes , servicios, secrets, configmaps y deployment, llega el momento de crear los deployment de las aplicaciones que hemos creado en Spring.
Por un lado tendremos el servicio, para exponer una aplicación que se ejecuta en un conjunto de Pods.
apiVersion: v1 kind: Service metadata: name: order-service spec: selector: app: order-service ports: - protocol: TCP port: 8080 nodePort: 30081 type: NodePort externalIPs: - 1.2.4.120
Y por otro lado tendremos el deployment de la propia aplicación. Aunque previamente, se tendrá que crear la imagen docker de la aplicación. Este deployment hará referencia al servicio, el deployment que a continuación escribimos, tendrá como variables, el usuario y contraseña de mongodb, que escribimos en el application.yaml de la aplicación:
apiVersion: apps/v1 kind: Deployment metadata: name: order-service spec: selector: matchLabels: app: order-service replicas: 2 template: metadata: labels: app: order-service spec: containers: - name: order-service image: order-service:latest imagePullPolicy: Never ports: - containerPort: 8080 env: - name: MONGO_USERNAME valueFrom: secretKeyRef: name: db-secret key: username - name: MONGO_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password
Este deployment hace referencia a la imagen order-service, que se habrá creado previamente mediante un Dockerfile que se encuentra en la aplicación.
kubectl create -f deployment.yaml
Verificar el correcto funcionamiento de todos los Pods
Verificamos que nuestros pods están running ejecutando el siguiente comando:
kubectl get pods
o también
kubectl get po
Si el estado no es running podemos ejecutar
kubectl logs -f <nombre-pod>
para ver los logs de la aplicación.
Si todo es correcto desde un terminal podemos hacer
minikube service shop-service
para arrancar el navegador y ver lo que muestra.
Conclusión
En esta entrada de Microservicios con Spring Cloud Kubernetes, hemos visto como podemos montar una arquitectura de una manera rápida y eficaz haciendo uso de las principales características que nos ofrece Kubernetes. En nuestro github podrás encontrar todo el proyecto.
Si tienes alguna duda o sugerencia no dudes en comentarlo.
Otros artículos que te pueden interesar
Arquitectura de Kubernetes: Master Node
Arquitectura de Kubernetes: Worker Node
1 pensamiento sobre “Microservicios con Spring Cloud Kubernetes”