Monitorizar tus aplicaciones en Kubernetes con Prometheus

Un tema muy importante del que todavía no te había hablado es de la monitorización de tus aplicaciones en Kubernetes. Es por ello que creo que debo empezar por el sistema más extendido dentro de este tipo de entornos llamado Prometheus. En este artículo te cuento cómo instalarlo, cómo visualizar las métricas y cómo hacer que tus aplicaciones se integren con él.

¿Qué es Prometheus?

Se trata de un sistema de monitorización de métricas, y generador de alertas, creado por SoundCloud, los que a su vez son ex-empleados de Google. Estos se inspiraron en el sistema de monitorización Borgmon, que se utilizaba para Kubernetes cuando este todavía no era un producto público. Este proyecto forma parte de la Cloud Native Computing Foundation.

Arquitectura de Prometheus

Prometheus utiliza un modelo HTTP pull, es decir es él quien va a por las métricas a las aplicaciones que se las exponen (llamadas exporters) y no al revés, aunque existe la posibilidad de que sea a la inversa si dicha aplicación tiene un tiempo de vida limitado, como un job, dejando sus métricas en una pieza llamada Pushgateway. Es capaz de descubrir las aplicaciones que tiene que monitorizar, como veremos después, y normalmente se utilizan herramientas de visualización externas, como Grafana, para explotar las métricas que recoge. También puede generar alertas en base a las métricas recogidas.

Instalar Prometheus con Helm

La forma más sencilla de instalar Prometheus es a través de Helm. Existen diferentes paquetes para hacerlo, pero en este artículo voy a utilizar el que instala únicamente el servidor de métricas. Antes de lanzar la instalación, necesito acudir al repositorio del chart en GitHub llamado stable/prometheus y copiar el archivo values.yml, para modificar algunos de los valores por defecto. Para este ejemplo he cambiado el intervalo de tiempo en el que Prometheus va a buscar las métricas a las aplicaciones:

  global:
    ## How frequently to scrape targets by default
    ##
    scrape_interval: 15s
    ## How long until a scrape request times out
    ##
    scrape_timeout: 10s
    ## How frequently to evaluate rules
    ##
    evaluation_interval: 30s

Para desplegarlo en Kubernetes puedes utilizar este comando con el archivo values.yaml que acabas de modificar:

helm install --namespace monitoring --name prometheus stable/prometheus -f prometheus/values.yml

Como puedes ver, he creado un namespace específico para este despliegue llamado monitoring. Una vez que finalice podrás acceder al servidor utilizando estos dos comandos:

export POD_NAME=$(kubectl get pods --namespace monitoring -l "app=prometheus,component=server" -o jsonpath="{.items[0].metadata.name}")

kubectl --namespace monitoring port-forward $POD_NAME 9090

El primero simplemente recupera el nombre del pod que se corresponde con el servidor de Prometheus. El segundo hace un port forward a dicho pod, mapeando tu puerto local 9090 con este. Si accedes a http://localhost:9090/ deberías de ver la interfaz de Prometheus.

Como ves, lo primero con lo que te encuentras es un cuadro de texto donde puedes introducir consultas sobre las métricas que está recogiendo. Como te puedes imaginar, ahora mismo está recuperando pocas, pero al menos las suyas propias y las del sistema.

No voy a entrar en cómo hacer consultas sobre las métricas. Para ello puedes ver ejemplos de consultas en la documentación oficial. Lo que sí quiero que veas es cómo puedes hacer que tus aplicaciones se integren con Prometheus.

Integrar una aplicación .NET Core con Prometheus

Existen varias librerías para integrar tus aplicaciones con Prometheus, las cuales están recogidas en la documentación oficial. Para este artículo te voy a mostrar cómo puedes integrar tu aplicación con ASP.NET Core. Si quieres hacerlo con el mismo ejemplo que yo, estoy utilizando la API que me cree para enseñarte cómo depurar pods en Kubernetes desde tu local, que a su vez está conectada a un MongoDB que utilicé para mostrarte cómo funcionan los recursos de tipo StatefulSet. En ella añado el paquete de Nuget llamado prometheus-net.AspNetCore.

A nivel de código, la única configuración que debo añadir para recuperar las métricas mínimas es en el Startup.cs, en el método Configure:


        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();
            app.UseHttpMetrics();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapMetrics();
                endpoints.MapControllers();
            });
        }

Como ves, sólo necesitas usar app.UseHttpMetrics, después de app.UseRouting(), y app.UseEndpoints para habilitar el endpoint que necesita Prometheus para recoger las métricas de tu aplicación.

Publica tu imagen en tu Docker Hub a través de docker build y push:

docker build . -t 0gis0/books-api
docker push 0gis0/books-api

Por último, para desplegar esta aplicación en tu Kubernetes puedes utilizar este manifiesto:

apiVersion: v1
kind: Namespace
metadata:
    name: bookstore

---

apiVersion: apps/v1
kind: Deployment
metadata:
    namespace: bookstore
    name: booksapi
    labels:
        app: bookstore
spec:
    replicas: 2
    selector:
        matchLabels:
            app: bookstore
    template:
        metadata:
            annotations:
                prometheus.io/scrape: "true"
                prometheus.io/port: "80"
            labels:
                app: bookstore
        spec:
            containers:
            - name: books-api
              image: 0gis0/books-api
              ports:
               - containerPort: 80

---

apiVersion: v1
kind: Service
metadata:
    name: booksapi-svc
    namespace: bookstore
spec:
    selector:
        app: bookstore
    ports:
    - protocol: TCP
      port: 80
      targetPort: 80

---

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: booksapi
    namespace: bookstore
spec:
    rules:
    - host: booksapi.TU_IP.nip.io
      http:
        paths:
        - backend:
            serviceName: booksapi-svc
            servicePort: 80
          path: /

En este él puedes ver que despliego diferentes recursos:

  • Namespace: Creo uno nuevo llamado bookstore para organizar dentro de él todos los recursos relacionados con mi aplicación.
  • Deployment: Este se encargará de desplegar la aplicación del ejemplo. Date cuenta de que he añadido como parte de la plantilla de los pods dos anotaciones para Prometheus llamadas prometheus.io/scrape:true y prometheus.io/port:80. Estas dos son las que busca Prometheus para marcar un pod como target y comenzar a recuperar las métricas que este proporcione.
  • Service: se encargará de balancear entre las diferentes réplicas del despliegue anterior, en este caso 2.
  • Ingress: si quieres utilizar un Ingress Controller para acceder a tu aplicación desde el exterior puedes seguir el artículo donde explico cómo configurarlo con Helm y nip.io.

Una vez que despliegues este manifiesto podrás comprobar que la aplicación está funcionando correctamente a través de http://booksapi.TU_API.nip.io/api/books. Otra de las cosas que debes probar es si efectivamente, con la librería que hemos incluido, se están generando métricas. Para ello necesitas ir a http://booksapi.TU_IP.nip.io/metrics

Como puedes ver, simplemente agregando las métricas por defecto ya tenemos unas cuantas bastantes representativas. Si quieres, puedes crear tus propias métricas siguiendo las indicaciones de la documentación de la librería.

Cómo ver tus métricas en Prometheus

Gracias a las anotaciones tu aplicación queda registrada como target, lo cual se puede comprobar a través de http://localhost:9090/targets

Prometheus estará cada 15 segundos consultando las métricas que expone. Por otro lado, en el apartado http://localhost:9090/graph podrás lanzar consultas contra dichas métricas.

Usando Grafana

Como te puedes imaginar, la interfaz de Prometheus se utiliza para consultas ocasionales o depuración. Lo más común es que quieras montarte tus propios paneles donde tener una visión global de tu aplicación, sin tener que lanzar queries continuamente. En la propia documentación de Prometheus recomiendan Grafana para ello, por lo que vamos a instalarla también a través de Helm.

Al igual que con Prometheus, me he descargado el archivo values.yml de stable/grafana y he modificado el apartado ingress para poder acceder a través de mi Ingress Controller:

ingress:
  enabled: true
  # Values can be templated
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  labels: {}
  path: /
  hosts:
    - grafana.TU_IP.nip.io 

Para desplegar el chart, utilizamos el mismo namespace donde ubicamos el servidor de Prometheus:

helm install --namespace monitoring --name grafana stable/grafana -f grafana/values.yml

Una vez lo despliegues necesitarás recuperar la contraseña del administrador a través de este comando:

kubectl get secret grafana -n monitoring -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

Con el hostname indicado, http://grafana.TU_IP.nip.io, podrás acceder a la herramienta. Utiliza admin como usuario y la contraseña que acabas de recuperar.

Para configurar como data source Prometheus es muy sencillo: basta con hacer clic en Add data source y la primera opción que te aparecerá es Prometheus. Selecciónala y, si has seguido los pasos de este artículo, esta debería de ser la configuración que debes utilizar:

Configuración del Data source Prometheus en Grafana

En este ejemplo, al estar tanto Grafana como el servidor de Prometheus en el mismo namespace, monitoring, solo es necesario indicar el nombre del servicio, prometheus-server, para que Grafana pueda acceder a él. Haz clic en Save & Test para guardar la configuración.

Por último, para ver algunas métricas de tu aplicación puedes instalar este dashboard: ASP.NET Core – controller summary (Prometheus). Para darle un poco de emoción, puedes ejecutar este contenedor, que hará que las mismas se muevan un poco:

kubectl run -i --tty load-test --image=busybox /bin/sh
while true; do wget -q -O- http://booksapi-svc.bookstore.svc.cluster.local/api/books; done

Si lo lanzas N veces, el resultado será parecido a este:

¡Saludos!