Actualmente, en el mundo de las plataformas, DevOps, cloud, etc… hay una gran cantidad de herramientas, muchas de las cuales se solapan en funcionalidad. Esto complica la elección de las “herramientas perfectas” para tu proyecto.
En el mercado, hay muchas herramientas que se han convertido en un estandar. Y OJO!, no digo que sean las únicas ni las mejores para tu proyecto, simplemente que tienen una gran comunidad detrás y su uso está más que extendido. Vease, por ejemplo, en el área de la monitorización, Prometheus+Grafana.
Como siempre digo, la mejor forma para aprender es hacer. Por ello me he propuesto analizar herramientas, en este caso la gran mayoría de la CNCF, y realizar un proyecto incremental de montar una plataforma/arquitectura para microsevicios. El objetivo no es profundizar en cada una de las herramientas que usemos, más bien es quedarnos en una capa intermedia en la que podamos ver las ventajas e inconvenientes que nos ofrecen las herramientas y cómo se integran con el resto de componentes.
¿Cómo vamos a empezar?
Antes hemos hablado de herramientas que son casi un estandar en la industria DevOps. En microservicios y contenedores se lleva la palma Kubernetes. Existen muchas variantes (EKS, AKS y GKE para cloud, OpenShift, etc…), en nuestro caso, y teniendo en cuenta lo que dijimos de que no vamos a entrar en detalle, podemos usar Minikube o Kind para tener disponible K8s. En mi caso me he decantado por Kind, que ya lo tenía montado para mis laboratorios.
En el cluster que montemos vamos a tener un par de “microservicios”, simples, que estarán escritos en Go. Los que me conocen saben lo pesado que estoy con Go… soy un poco fatiga :D. Yo solo doy algún dato, de los proyectos graduados de la CNCF, el 75% usan como lenguaje principal Go. Si hablamos de los proyectos que se están incubando, el procentaje baja al 70%, que igualmente me parece alto. ¿Quiere decir algo esto? Posiblemente no, pero quería dar ese dato jajaja.
No me voy a dilatar más. Simplemente comentar que estoy abierto a sugerencias de herramientas a usar en este “proyecto”.
Arquitectura
La arquitectura propuesta para esta solución será sencilla. Contaremos con un cluster de 3 nodos, donde se expondrán los servicios hacía el “exterior” con un controlador de Ingress (Nginx). En el cluster de Kubernetes tendremos dos “microservicios”. Uno hará las veces de frontend (este micro tendrá el Ingress), y el otro actuará como backend, que no será accesible desde el exterior directamente. No habrá bases de datos, ni volúmenes, ni nada. Simplemente los dos pods con el ejecutable de Go en su interior.
Aquí tenéis una imagen con la representación gráfica:
Cluster
En mi caso he elegido Kind para montar un cluster de 3 nodos que correrarán sobre Podman. Necesitamos tener instaldo el siguiente software en nuestro equipo:
- kubectl: Guía de instalación.
- Kind: Guía de instalación.
- Podman/Docker: Guía de instalación. Yo instalé Podman y luego me creé un alias en mi archivo
.zshrc
, algo redundante, porque podría haber instalado Docker… Pero bueno, ya está hecho jaja. Si te resulta más cómodo, puedes instalar directamente Docker y ya está.
Una vez instaladas las herramientas, procederemos a instalar el cluster con el siguiente archivo de configuración:
cluster-3-nodes.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
- role: worker
- role: worker
Como se puede ver, está preparada la configuración para poder meter el ingress que luego usaremos para acceder a las aplicaciones que montemos dentro del cluster.
Para finalizar con la instalación de cluster, simplemente ejecutamos el siguiente comando:
kind create cluster --name k8s-cluster001 --config cluster-3-nodes.yaml
En nuestro caso nos levantará 3 contenedores en Podman. Uno que actuará como control-plane y otros dos que actuarán como workers. Una vez finalizada la instalación, podemos listar los nodos para comprobar que están listos:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-cluster001-control-plane Ready control-plane 2d21h v1.31.0
k8s-cluster001-worker Ready <none> 2d21h v1.31.0
k8s-cluster001-worker2 Ready <none> 2d21h v1.31.0
Ingress (Nginx)
Hasta ahora tenemos montado nuestro cluster de Kubernetes, pero si instalamos alguna aplicación dentro, “no tendríamos” (port-forwarding) forma de acceder a las mismas. Así que vamos a instalar un Ingress para acceder a nuestras aplicaciones con alguna funcionalidad más que un simple puerto. Su funcionamiento es sencillo, es nuestro guardia de tráfico que se encarga de dirigir las solicitudes de los usuarios a los servicios dentro de nuestro cluster de Kubernetes.
No vamos a entrar en mucho detalle y vamos a utilizar el propio archivo que indica Kind en su guía de instalación:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
Si entras en la URL y ves el contenido, verás que tiene mucha información (namespace, serviceaccount, roles, deployment, etc…). Estoy suponiendo que más o menos entendéis lo que hay dentro, y en un futuro reemplazaremos esta instalación por una con Helm (spoiler) de otra herramienta.
Con esto hemos finalizado la instalación del nuestro controlador de Ingress. En las siguiente sección, veremos el uso de los recursos de tipo Ingress.
Microservicios
Es la hora de los microservicios, los cuales vamos a desarrollar en Go. Bueno, en realidad no hace falta que los desarrolléis, aquí tendréis los enlaces al código fuente. De igual forma, explicaremos qué es lo que hacen dichos microservicios.
Existirán dos microservicios, front
y back
. El front
simplemente estará escuchando peticiones en el puerto 8080 y mostrará una página web con un color de fondo. Veremos que para acceder, con el Ingress, no necesitaremos poner dicho puerto. Por otro lado, el back
estará escuchando peticiones también en el puerto 8080 y tendrá dos path API REST a los que accederá el frontend, /primario
y /secundario
. Este micro devolverá un JSON con la información del color, que se utilizará en el front
.
Aquí podéis encontrar los enlaces a los repositorios de los microservicios (ambos creados casi en su totalidad con GitHub Copilot):
En estos repositorios tenemos tanto el código fuente de las aplicaciones, como el resto de archivos para desplegarlo en Kubernetes. Aunque cada repo tiene los pasos en el README de cómo desplegar el aplicativo, los explicaremos aquí.
Para empezar, tenemos que consturir la imagen que vamos a desplegar en nuestro cluster de Kubernetes. Necesitaremos tener un archivo Dockerfile con las instrucciones para la construcción de la imagen:
# Utiliza una imagen base de Go
FROM golang:1.23-alpine
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copia el código fuente al contenedor
COPY . .
# Compila el binario
RUN go build -o frontend-microservice .
# Define el puerto en el que la aplicación escuchará
EXPOSE 8080
# Comando para ejecutar la aplicación
CMD ["./frontend-microservice"]
NOTA: Para el backend, solo habría que cambiar “frontend” por “backend”, debe funcionar igual.
A continuación construimos la imagen, la cual se guardará en nuestro repositorio local, en nuestro PC:
docker build -t frontend-microservice:1.0.0 .
Le pondremos el tag 1.0.0, ya que evolucionaremos la aplicación. Al momento de escribir este post, aunque son aplicaciones muy sencillas, se me ocurren muchas mejoras relacionadas con el despliegue en Kubernetes.
Ahora tenemos un pequeño problema… no tenemos aún container registry (Harbor, calienta que sales!!), y las imágenes están en local. Hay que pasar dichas imágenes al propio registry que tiene Kind. Yo tuve un problema con Podman (escribo docker, pero porque tengo un alias), no me dejaba subir la imagen directamente desde mi registry, tuve que descargar la imagen en formato tar y subir el archivo.
docker save frontend-microservice:1.0.0 -o frontend-microservice.tar
kind load image-archive frontend-microservice.tar --name k8s-cluster001
Con esto ya tenemos todo lo necesario para empezar a desplegar en Kubernetes. En el directorio “k8s” del repositorio están los archivos a desplegar (service, ingress, deployment). Queda fuera del alcance de este artículo explicar el contenido de los mismos, de momento os pido confianza ciega! jeje.
kubectl -n default apply -f k8s/
Esperamos unos 30 segundos y comprobamos que esté todo levantado correctamente con el siguiente comando:
kubectl -n default get all,ingress
Deberíamos ver una salida como esta:
NAME READY STATUS RESTARTS AGE
pod/frontend-deployment-7dcd4d6c4f-hncb2 1/1 Running 0 40s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/frontend-service ClusterIP 10.96.143.182 <none> 80/TCP 8m47s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 34d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/frontend-deployment 1/1 1 1 40s
NAME DESIRED CURRENT READY AGE
replicaset.apps/frontend-deployment-7dcd4d6c4f 1 1 1 40s
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/frontend-ingress <none> frontend.kind.cluster localhost 80 5m51s
Parece que está todo corriendo! Nos falta un último paso para probar en nuestro entorno local, modificar el /etc/hosts para poder acceder por URL a nuestro servicio. Solo tenemos que agregar la siguiente línea:
127.0.0.1 frontend.kind.cluster
Pruebas
Ya estamos a punto de finalizar esta primera parte! Vamos a probar lo que hemos creado!
Será sencillo, únicamente habría que escribir (o hacer click en) las siguientes URLs:
http://frontend.kind.cluster/primario
http://frontend.kind.cluster/secundario
Una de las URL mostrará un fondo verde y la otra azul.
En los siguientes post evolucionaremos esta simple arquitectura, añadiendo nuevas herramientas y funcionalidades. Estad atentos!
GL & HF!