Engineering

Tutorial sobre observabilidad de Kubernetes: Monitoreo de rendimiento de aplicaciones con Elastic APM

Este blog es el tercero de la serie de tutoriales sobre observabilidad de Kubernetes; exploraremos cómo puedes monitorear todos los aspectos de tus aplicaciones que se ejecutan en Kubernetes, incluidos los siguientes:

Hablaremos sobre usar Elastic Observability para realizar el monitoreo de rendimiento de aplicaciones con Elastic APM.

Antes de comenzar: para el siguiente tutorial debes tener un entorno de Kubernetes configurado. Creamos un blog complementario en el cual se te guía por el proceso de configurar un entorno Minikube de un solo nodo con una aplicación de muestra para ejecutar el resto de las actividades.

Monitoreo de rendimiento de aplicaciones

APM se enfoca en la medición automática de indicadores de nivel de servicio (SLI) clave orientados al usuario: latencia de solicitud/respuesta y errores que recibe el usuario. Gracias a un monitoreo efectivo de estos, puedes encontrar rápidamente el componente (incluso el bloque de código) responsable de problemas como degradación del rendimiento o un aumento en la cantidad de errores. APM proporciona una excelente herramienta de priorización de primer nivel que puede identificar la causa raíz del problema, reduciendo el tiempo promedio de respuesta (MTTR).

Rastreo distribuido con Elastic APM

Elastic APM soporta el rastreo distribuido, lo que permite medir la latencia de una solicitud/respuesta de extremo a extremo de diferentes componentes de aplicación distribuida que participan para atender la misma solicitud de usuario. La app APM muestra la duración del rastreo en general y el desglose de las latencias relacionadas con los componentes que participan en el rastreo distribuido. Vayamos a la app APM en Kibana y veamos los rastreos y las transacciones. Nota: Asegúrate de generar un poco de tráfico de usuario haciendo clics dentro de la app petclinic primero.

Distributed tracing in Elastic APM

Rastreos en contexto con logs y métricas

Cuando se trata de desplegar una aplicación en Kubernetes, el rastreo distribuido y APM siguen proporcionando el beneficio de poder priorizar rápidamente los problemas al tiempo que capturan y establecen una referencia cruzada con otras piezas del rompecabezas de observabilidad: logs y métricas. Con cada una de estas piezas al alcance de la mano, la solución de problemas de picos de latencia puede comenzar por reducir el alcance de la investigación a un solo componente con APM, y se puede vincular con facilidad a las métricas de uso de CPU y memoria y las entradas del log de errores de un pod de Kubernetes en particular, todo sin salir de Kibana.

Ahora, gracias a los procesadores en Beats y los metadatos que recopilan los agentes de APM, se establece una referencia cruzada para todos los datos de observabilidad en Kibana. Puedes comenzar a observar los rastreos de APM, consultar las métricas de los pods que fueron parte del procesamiento de ese rastreo y ver los logs excluidos por los componentes que se ejecutaban cuando se procesó el rastreo, todo en el mismo lugar.

With Elastic APM, it's easy to correlate traces and log data.

Quickly jump from APM traces to infrastructure metrics in Kibana

Despliegue de agentes de Elastic APM

Los agentes de APM se despliegan junto con los componentes de la aplicación a la que monitorean. Con Kubernetes, los componentes de la aplicación se hacen parte del código que se ejecuta en los pods. En este tutorial, usamos dos agentes: el agente JavaScript de monitoreo de usuario real (RUM) de APM y el agente Java de APM.

Agente Java de Elastic APM

Esta es la parte de inicialización del agente Java de APM en el descriptor de despliegue del pod de petclinic $HOME/k8s-o11y-workshop/petclinic/petclinic.yml:

          env:
          - name: ELASTIC_APM_SERVER_URLS
            valueFrom:
              secretKeyRef:
                name: apm-secret
                key: apm-url
          - name: ELASTIC_APM_SECRET_TOKEN
            valueFrom:
              secretKeyRef:
                name: apm-secret
                key: apm-token
          - name: ELASTIC_APM_SERVICE_NAME
            value: spring-petclinic-monolith
          - name: ELASTIC_APM_APPLICATION_PACKAGES
            value: org.springframework.samples

El agente de APM está incluido como una dependencia en el archivo pom.xml de la aplicación petclinic $HOME/k8s-o11y-workshop/docker/petclinic/pom.xml:

<!-- Dependencias de Elastic APM -->
        <dependency>
            <groupId>co.elastic.apm</groupId>
            <artifactId>apm-agent-attach</artifactId>
            <version>${elastic-apm.version}</version>
        </dependency>
        <dependency>
            <groupId>co.elastic.apm</groupId>
            <artifactId>apm-agent-api</artifactId>
            <version>${elastic-apm.version}</version>
        </dependency>
        <dependency>
            <groupId>co.elastic.apm</groupId>
            <artifactId>elastic-apm-agent</artifactId>
            <version>${elastic-apm.version}</version>
        </dependency>
        <!-- Fin de dependencias de Elastic APM -->

Esta forma de desplegar integra el agente Java como una dependencia Maven. Existen otras formas de desplegar los agentes de APM, como adjuntos en el tiempo de ejecución con el agente Java. Consulta la documentación sobre el agente Java de Elastic APM para obtener detalles.

Agente de monitoreo de usuario real (RUM) de Elastic APM

El agente RUM se ejecuta como parte de la aplicación del navegador del usuario y proporciona todas las métricas orientadas al usuario directamente desde el navegador. En este tutorial, se usa precisamente para eso, al igual que como punto de partida para los rastreos distribuidos. Aquí es donde se instancia el agente de APM en el código Javascript del lado del usuario $HOME/k8s-o11y-workshop/docker/petclinic/src/main/resources/templates/fragments/layout.html:

 <script th:inline="javascript">
...
    var serverUrl = [[${apmServer}]];
    elasticApm.init({
     serviceName: 'petclinic-frontend',
     serverUrl: serverUrl,
     distributedTracingOrigins: [],
     pageLoadTransactionName: pageName,
     active: true,
     pageLoadTraceId: [[${transaction.traceId}]],
     pageLoadSpanId: [[${transaction.ensureParentId()}]],
     pageLoadSampled: [[${transaction.sampled}]],
     distributedTracing: true,
    })
...
 </script>

Petclinic es una aplicación que se procesa del lado del servidor, Thymeleaf es un marco de trabajo que muestra plantillas que se usa con Spring Boot y, como tal, completa algunos valores que se envían al front-end, en el código Java del controlador. Este es un ejemplo de cómo el atributo del modelo transaction se completa en $HOME/k8s-o11y-workshop/docker/petclinic/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java:

    @ModelAttribute("transaction")
    public Transaction transaction() {
        return ElasticApm.currentTransaction();
    }

Monitoreo de errores

Los agentes de APM también capturan excepciones no controladas. Intenta hacer clic en el menú “ERROR” y consulta la app APM en Kibana para ver los detalles de la excepción generada.

Our sample application

Elastic APM can show you all your application errors in a click

Este es el código Java responsable de cómo el agente de APM detecta las excepciones no controladas generadas por la aplicación, $HOME/k8s-o11y-workshop/docker/petclinic/src/main/java/org/springframework/samples/petclinic/system/CrashController.java:

    @GetMapping("/oups")
    public String triggerException() {
        throw new RuntimeException("Expected: controller used to showcase what "
                + "happens when an exception is thrown");
    }

Monitoreo de métricas de tiempo de ejecución

Los agentes están desplegados junto con los componentes de la aplicación en las métricas de tiempo de ejecución de recopilación y tiempo de ejecución. Por ejemplo, el agente Java las recopila desde el primer uso sin necesidad de proporcionar ningún código o configuración, excepto por habilitar la recopilación de métricas.

Runtime metrics in Elastic APM

Mapas de servicios

En Elastic APM 7.7 se presentó la versión beta de los mapas de servicio, una representación gráfica de las relaciones representadas en los rastreos de APM. En esta vista se muestran los componentes involucrados en los rastreos que se muestran en la app APM. Nuestra aplicación es muy simple, solo un cliente de navegador con backend MySQL y Java, de modo que el mapa resultante será bastante simple.

Service Maps in Elastic APM

Recopilación de métricas de JMX con un agente de Elastic APM

El agente Java se puede configurar para recopilar métricas de JMX expuestas por la aplicación. El componente Petclinic en este tutorial está configurado para recopilar las métricas siguientes, $HOME/k8s-o11y-workshop/petclinic/petclinic.yml:

- name: ELASTIC_APM_CAPTURE_JMX_METRICS
  value: >-
   object_name[java.lang:type=GarbageCollector,name=*]    
     attribute[CollectionCount:metric_name=collection_count] 
     attribute[CollectionTime:metric_name=collection_time],
   object_name[java.lang:type=Memory] attribute[HeapMemoryUsage:metric_name=heap]

Visualización de métricas personalizadas con Lens

No todas las métricas están representadas en la app APM. Como en el ejemplo anterior, las métricas JMX son muy específicas de la aplicación y por lo tanto no se pueden visualizar dentro de la app APM. Además, a veces las métricas deben incluirse en otras visualizaciones o visualizarse de forma diferente para que tengan valor. Los dashboards y las visualizaciones de Kibana se pueden usar de forma nativa para visualizar estas métricas, pero nos gustaría mostrarte una forma nueva y emocionante de hacerlo incluso más rápido.

Recientemente, se presentó Lens en Kibana como una herramienta de visualización más intuitiva impulsada por analistas. En este ejemplo se puede ver cómo se puede usar Lens para visualizar una métrica de JMX personalizada recopilada por el agente.

Ejemplo de Lens

Para hacer este ejemplo más interesante, ejecutemos un comando scale-out para aumentar el recuento de pods del componente petclinic, así obtendremos varias líneas por JVM en ejecución.

$ kubectl scale --replicas=3 deployment petclinic-deployment
# Valida que scale-out haya hecho lo esperado.
$ kubectl get pods

Deberías ver lo siguiente:

NAME                                    READY   STATUS    RESTARTS   AGE
mysql-deployment-7ffc9c5897-grnft       1/1     Running   0          37m
nginx-7ff654f859-xjqgn                  1/1     Running   0          28m
petclinic-deployment-86b666567c-5m9xb   1/1     Running   0          9s
petclinic-deployment-86b666567c-76pv7   1/1     Running   0          9s
petclinic-deployment-86b666567c-gncsw   1/1     Running   0          30m
theia-86d9888954-867kk                  1/1     Running   0          43m

Ahora, aquí viene el poder de Lens:

Lens in actions!

Barra de búsqueda, precisamente para hacer búsquedas

Por supuesto, la app Elastic APM tiene una barra de búsqueda. Y es excelente para buscar una aguja en un pajar y reducir el alcance del problema que intentas evaluar. Por ejemplo, aquí verás cómo la vista de UI de APM puede reducirse a un tipo de navegador en particular:

Elastic APM has powerful search functionality because it's built on... Elasticsearch

Correlación entre logs y rastreos de APM

Otro ejemplo útil en el que la totalidad es más que sus partes constituyentes es correlacionar los rastreos de APM con las entradas de log producidas por el código rastreado. Los rastreos de APM se pueden vincular a las entradas de log a través del campo trace.id<code>. Y todo sucede sin mucho esfuerzo, solo algunas configuraciones simples. Primero, veamos un ejemplo de esta correlación.

Echemos un vistazo a un rastreo:

Correlate traces and logs with a click

Este rastreo nos muestra la vista de línea de tiempo de cómo se ejecutaron las distintas partes del código, ahora veamos los logs que generó el código que acabamos de rastrear. Seleccionaremos Trace logs en el menú Actions. Nos llevará a la UI de Logs, preseleccionará la hora en que se capturaron los datos de rastreo y usará trace.id para filtrar los datos de log que tengan anotaciones con la misma trace.id:

Log streams for your trace

Drilling down into a trace id

Obviamente, trace.id es inherente a los rastreos de APM, pero ¿cómo logramos enriquecer los datos de logs con ella? Primero, como estamos usando el agente Java de Elastic APM, usamos la característica de correlación de logs que implementa. En esencia, completa los campos trace.id y transaction.id en el mapa de contexto MDC del marco de trabajo de logging de Java (logback en el caso de Spring Boot). Todo lo que se necesita es configurar la variable de este entorno en petclinic ConfigMap petclinic/petclinic.yml:

          - name: ELASTIC_APM_ENABLE_LOG_CORRELATION
            value: "true"

Después, se configura el logging de la app petclinic con logging de ECS que enriquece las entradas de log enviadas al Elastic Stack con campos adicionales correspondientes a Elastic Common Schema, como log.level, transaction.id, etc. Para habilitarlo, incluimos la siguiente dependencia en pom.xml de la aplicación petclinic:

        <dependency>
            <groupId>co.elastic.logging</groupId>
            <artifactId>logback-ecs-encoder</artifactId>
            <version>${ecs-logging-java.version}</version>
        </dependency>

También está el archivo docker/petclinic/src/main/resources/logback-spring.xml con logging de ECS configurado para escribirse como JSON en stdout:

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="co.elastic.logging.logback.EcsEncoder">
        <serviceName>petclinic</serviceName>
      </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="console"/>
    </root>

Por último, está la anotación en petclinic ConfigMap ( petclinic/petclinic.yml) que aprovecha el autodescubrimiento de beats para instruir a filebeat que parsee el JSON resultante generado por petclinic:

container:
      annotations:
...
        co.elastic.logs/type: "log"
        co.elastic.logs/json.keys_under_root: "true"
        co.elastic.logs/json.overwrite_keys: "true"

Entonces, para permitir que funcione esta correlación, debemos habilitar ambos, el agente Java y el marco de trabajo de logging para que registren correlaciones de rastreo, y podemos vincular las dos piezas de datos de observabilidad entre sí.

Así concluye la serie

Logs, métricas y APM... ¡lo logramos! En esta serie de blogs, observamos cómo instrumentar una aplicación para recopilar sus logs, métricas y rastreos de APM con el Elastic Stack usando Filebeat, Metricbeat y APM. En el tutorial también se demuestra cómo recopilar logs y métricas de Kubernetes usando los mismos componentes. Hay componentes adicionales en el ecosistema de Elastic que pueden agregar más detalles para completar el panorama de la observabilidad de tu entorno de Kubernetes:

  • Heartbeat: una forma excelente de medir el tiempo de actividad y la capacidad de respuesta de tu aplicación y todo el entorno de Kubernetes. Puede desplegarse fuera del cluster, más cerca de tus usuarios. Heartbeat puede ilustrar cómo los usuarios ven tu aplicación, el tipo de red y la latencia de respuesta que obtienen, y a cuántos errores están expuestos.
  • Packetbeat: obtén una vista del tráfico de red del cluster de Kubernetes interno, intercambio de certificados TLS, búsquedas DNS, etc.
  • Incluimos un despliegue de muestra de la notebook Jupyter y agregamos una notebook de muestra que ilustra cómo puedes obtener acceso a los datos de observabilidad sin procesar almacenados en Elasticsearch, para que puedas aplicar la ciencia de los datos como un experto:
    k8s-o11y-workshop/jupyter/scripts/example.ipynb
        

No dudes en convertirte en contribuidor del repositorio de Github o crea un ticket de Github si algo no funciona como debería.

Puedes comenzar a monitorear tus sistemas e infraestructura hoy. Regístrate para una prueba gratuita de Elasticsearch Service en Elastic Cloud o descarga el Elastic Stack y hospédalo tú mismo. Una vez en marcha, monitorea la disponibilidad de tus hosts con Elastic Uptime e instrumenta las aplicaciones que se ejecutan en tus hosts con Elastic APM. Estarás camino a un sistema completamente observable, integrado por completo con tu cluster de métricas nuevas. Si encuentras algún obstáculo o tienes preguntas, visita nuestros foros de debate; estamos aquí para ayudarte.