K8s: Probando servicios desplegados

Martín Saporiti
Flux IT Thoughts
Published in
5 min readJul 8, 2020

--

Kubernetes es un mundo y cuando desplegamos algo, lo primero que queremos hacer es “pegarle” y probarlo. En este artículo describo algunas alternativas simples para validar o testear los servicios que desplegamos en un cluster de Kubernetes. La idea es poder invocar a un servicio desplegado en k8s y obtener una respuesta.

Primero, algunos conceptos

De acuerdo a la documentación oficial de Kubernetes, se pueden definir cuatro tipos de servicios¹:

  • ClusterIP: expone el servicio en una IP interna del clúster. Al elegir este valor, solo se puede acceder al Servicio desde el clúster. Este es el tipo de servicio predeterminado.
  • NodePort: expone el servicio en la IP de cada nodo en un puerto estático (el NodePort). Se crea automáticamente un Servicio ClusterIP, hacia el cual se enruta el Servicio NodePort. Podremos ponernos en contacto con el servicio NodePort, desde fuera del clúster, invocando a <NodeIP>: <NodePort>.
  • LoadBalancer: expone el Servicio externamente usando el balanceador de carga de un proveedor de la nube. Los servicios NodePort y ClusterIP, a los que se enrutan las rutas externas del balanceador de carga, se crean automáticamente.
  • ExternalName: asigna el servicio al contenido del campo externalName (por ejemplo, foo.bar.example.com), devolviendo un registro CNAME

En este artículo, estaremos trabajando con un servicio desplegado como ClusterIP, de manera que solamente pueda ser accedido desde dentro del cluster. Ahora bien, puede ocurrir que por diversas razones y, momentáneamente necesitemos poder invocar al servicio desde afuera del cluster. Veremos cómo hacerlo. También veremos como “meternos” dentro del cluster e invocar al servicio desde otro pod. Todas estas opciones, dependiendo del contexto y la urgencia, son realmente útiles.

Antes de pasar a ejemplos sobre estas alternativas voy a explicar, de manera muy simple, la arquitectura de la aplicación a testear:

Arquitectura del Ejemplo

El ejemplo que utilizaremos para probar las opciones mencionadas consta de una simple aplicación, una suerte de API, que retorna frases famosas. Retorna Quotes. Estas quotes se almacenan en una base de datos Mongo que es consumida por una app desarrollada en GO, aplicación que expone un servicio REST. Todo bien básico, pero útil para chequear lo que se quiere mostrar.

Entonces, la idea es que, luego de realizado el despliegue en el cluster K8s, podamos invocar al servicio -la API- a través del comando CURL, simulando ser una app frontend u otro microservicio. A este llamado al servicio lo haremos desde dentro y fuera del cluster.

El archivo de despliegue del servicio (ClusterIP) tiene la siguiente pinta:

Lo más importante a explicar acá es que la app internamente, dentro del contenedor, escucha el puerto 3000 y fuera del contenedor atiende en el puerto 80. No tiene mucha magia. Básicamente mapeamos el puerto 3000 al 80.

Veamos los servicios que tenemos entonces desplegados:

Como muestro en la imagen anterior, se pueden apreciar dos servicios desplegados. El servicio que atiende las peticiones, la Mongo y el servicio que atiende las aplicaciones a la app de quotes. Ambos son de tipo ClusterIP y solamente podemos acceder a ellos desde dentro del cluster.

Explicada la arquitectura y la idea general, veamos algunas de las opciones con las que contamos.

Opción 1: Port-Forward

Esta opción consiste en hacer un forward desde el puerto donde atiende el servicio a un puerto de nuestra máquina. Esta opción es temporal y no es insegura, teniendo en cuenta esa temporalidad. Además, requiere acceso al cluster a través de la API. La forma genérica de hacerlo es:

En nuestro ejemplo sería:

Luego, desde nuestra terminal ejecutamos curl localhost:8080 y obtenemos:

Bárbaro, anduvo. Veamos otra opción.

Opción 2: Bastión

Una segunda opción es crear un bastión (temporal) dentro del cluster para poder invocar el servicio. Por lo general se utilizan contenedores livianos, simples, que permitan realizar una llamada mediante curl:

Con el comando anterior, nos metemos dentro del contenedor y podemos ejecutar:

y obtenemos:

Éxito, salió.

Antes de pasar a la siguiente opción vale la pena mencionar algo. En la primera opción hicimos un port-forward del puerto del contenedor dentro del cluster: es por eso que llamamos al puerto 3000. En la segunda opción, estamos llamando al servicio que está delante del pod: por este motivo, lo invocamos a través del puerto 80.

Opción 3: NodePort

Esta opción consiste en -temporalmente- cambiar el tipo de servicio para que pase a ser de tipo NodePort. Es medianamente insegura porque, ante un olvido, nos quedaría un servicio expuesto fuera del cluster. Dependiendo del contexto esto puede no ser conveniente. Hay que modificar, entonces, la definición del servicio en el archivo .yml, quedando con esta facha:

Aplicados los cambios, ejecutamos

Entonces ahora podemos pegarle a la EXTERNAL-IP (y el puerto 3001) y obtener una respuesta.

Pero… ¿qué pasó? ¿Por qué dice <none>? Dado que este ejemplo está implementado utilizando Minikube, es decir un cluster de juguete, hay que hacer un paso diferente. Tenemos que obtener la IP del cluster:

y ahora sí, podemos invocar a curl http://192.168.64.3:30001/ y obtener:

Gol, funca.

Bonus: Ingress

Para cerrar el artículo, veamos una opción más… colocar un ingress adelante del servicio de manera temporal para poder probarlo. El Ingress es la puerta de entrada al cluster. Cada cluster tiene su propia implementación de Ingress. Vamos a crearlo, entonces, con un archivo .yml:

Algo importante a mencionar es que si lo estamos probando localmente, tenemos que modificar el archivo /etc/host para que quotes-app.info esté mapeada a nuestra IP.

Luego, podemos hacer curl quotes-app.info/ y obtener una quote.

Para terminar

No voy a decir nada nuevo, Kubernetes está buenísimo, simplifica muchísimo el despliegue de aplicaciones a través de contenedores y permite que un dev -o cualquier otro perfil con ganas- ponga software en producción de manera muy simple. Este artículo es mi humilde aporte a todos los que están aprendiendo K8s y se toparon con la duda: ¿cómo hago para saber si el servicio que desplegué está corriendo?

Podés encontrar el código fuente que usé en https://github.com/fluxitsoft/quotes-k8s-sample

¹ https://kubernetes.io/docs/concepts/services-networking/service/

Conocé más sobre Flux IT: Website · Instagram · LinkedIn · Twitter · Dribbble · Breezy

--

--