Tutorial de observabilidade do Kubernetes: Monitoramento de performance de aplicação com o Elastic APM

Este post é o terceiro da nossa série de tutoriais de observabilidade do Kubernetes, onde exploramos como você pode monitorar todos os aspectos das suas aplicações em execução no Kubernetes, incluindo:

Discutiremos o uso do Elastic Observability para realizar o monitoramento de performance de aplicação (APM) com o Elastic APM.

Antes de começar: para o tutorial a seguir, é necessário ter um ambiente do Kubernetes configurado. Criamos um post suplementar que mostra o processo de configuração de um ambiente do Minikube de nó único com uma aplicação de demonstração para executar o restante das atividades.

Monitoramento de performance de aplicação

O APM se concentra na mensuração automática dos principais indicadores de nível de serviço (SLI) voltados para o usuário: latência da solicitação/resposta e erros voltados para o usuário. Ao monitorá-los com eficácia, você pode encontrar rapidamente o componente (até mesmo o bloco de código) responsável por problemas como degradação de desempenho ou aumento na quantidade de erros. O APM fornece uma excelente ferramenta de triagem de primeiro nível que pode identificar a causa raiz do problema, reduzindo o tempo médio de resposta (MTTR).

Rastreamento distribuído com o Elastic APM

O Elastic APM dá suporte para o rastreamento distribuído, que permite mensurar a latência de uma solicitação/resposta de ponta a ponta de diferentes componentes de uma aplicação distribuída que participam do atendimento à mesma solicitação do usuário. O app APM exibe a duração geral do trace, bem como o detalhamento das latências relacionadas aos componentes que participam do rastreamento distribuído. Vamos ver o app APM no Kibana e conferir os traces e as transações. Observação: certifique-se de gerar algum tráfego de usuário clicando primeiro na aplicação petclinic!

Rastreamento distribuído no Elastic APM

Traces em contexto com logs e métricas

Quando se trata de implantar uma aplicação no Kubernetes, o rastreamento distribuído e o APM continuam a fornecer o benefício da capacidade de fazer a triagem de problemas rapidamente, ao mesmo tempo em que capturam e fazem a referência cruzada com outras peças do quebra-cabeça da observabilidade: logs e métricas. Com cada uma dessas peças ao seu alcance, a solução de problemas de pico de latência pode começar restringindo o escopo da investigação a um único componente com o uso do APM e pode ser facilmente vinculada a métricas de utilização de CPU e memória e entradas de log de erros de um pod do Kubernetes específico, tudo sem sair do Kibana.

Agora, graças aos processadores nos Beats e aos metadados coletados pelos agentes do APM, é possível fazer a referência cruzada de todos os dados de observabilidade no Kibana. Você pode começar analisando os traces de APM, conferir as métricas dos pods que fizeram parte do processamento desse trace e examinar os logs deixados pelos componentes executados no momento em que o trace foi processado, tudo no mesmo lugar.

Com o Elastic APM, é fácil correlacionar traces e dados de log.

Passe rapidamente dos traces de APM para as métricas de infraestrutura no Kibana

Implantação de agentes do Elastic APM

Os agentes do APM são implantados juntamente com os componentes da aplicação que monitoram. Com o Kubernetes, os componentes da aplicação fazem parte do código que está sendo executado nos pods. Neste tutorial, estamos usando dois agentes: o Agente JavaScript de monitoramento de usuário real (RUM) do APM e o Agente Java do APM.

Agente Java do Elastic APM

Esta é a parte de inicialização do Agente Java do APM no descritor da implantação do pod do 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

O agente do APM é incluído como uma dependência no arquivo pom.xml da aplicação petclinic $HOME/k8s-o11y-workshop/docker/petclinic/pom.xml:

<!-- Dependências do 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>
        <!-- Fim das dependências do Elastic APM -->

Esta forma de implantação incorpora o Agente Java como uma dependência do Maven. Existem outras maneiras de implantar os agentes do APM, como o anexo de tempo de execução com o Agente Java. Consulte a documentação do Agente Java do Elastic APM para obter detalhes.

Agente de monitoramento de usuário real (RUM) do Elastic APM

O Agente de RUM é executado como parte da aplicação do navegador do usuário e fornece todas as métricas voltadas para o usuário diretamente do navegador. Neste tutorial, ele é usado exatamente para isso, além de ser o ponto de partida para traces distribuídos. É aqui que o agente do APM é instanciado no código Javascript do lado do usuário $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>

A aplicação petclinic é renderizada no lado do servidor, e o Thymeleaf é um framework de renderização de modelo usado com o Spring Boot. Como tal, preenche alguns dos valores enviados para o frontend, no código Java do controlador. Aqui está um exemplo de como o atributo de modelo transaction está sendo preenchido em $HOME/k8s-o11y-workshop/docker/petclinic/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java:

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

Monitoramento de erros

Os agentes do APM também capturam exceções não tratadas. Experimente clicar no menu “ERROR” (Erro) e verifique os detalhes da exceção gerada no app do APM no Kibana.

Nossa aplicação de amostra

O Elastic APM pode mostrar todos os erros da sua aplicação com um clique

Este é o código Java responsável pela maneira como as exceções não tratadas geradas pela aplicação são capturadas pelo agente do APM. $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");
    }

Monitoramento de métricas de tempo de execução

Os agentes são implantados em conjunto com os componentes da aplicação no tempo de execução e coletam métricas do tempo de execução. Por exemplo, o Agente Java as coleta prontamente, sem a necessidade de fornecer qualquer código ou configuração, além da habilitação da coleta de métricas.

Métricas de tempo de execução no Elastic APM

Mapas de serviços

O Elastic APM 7.7 introduziu a versão beta dos mapas de serviços, uma representação gráfica dos relacionamentos mostrados nos traces de APM. Esta visualização mostra quais componentes estão envolvidos nos traces exibidos no app do APM. Nossa aplicação é muito simples, apenas um cliente de navegador com backend Java e MySQL; por isso, o mapa resultante será bem simples.

Mapas de serviço no Elastic APM

Coleta de métricas do JMX com um agente do Elastic APM

O Agente Java pode ser configurado para coletar métricas do JMX expostas pela aplicação. O componente petclinic neste tutorial é configurado para coletar as seguintes métricas $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]

Visualização de métricas customizadas com o Lens

Nem todas as métricas são representadas no app do APM. Como no exemplo acima, as métricas do JMX são muito específicas para a aplicação e, portanto, não podem ser visualizadas dentro do app do APM. Além disso, às vezes, as métricas precisam fazer parte de outras visualizações ou ser visualizadas de uma maneira diferente para que sejam valiosas. As visualizações e os dashboards do Kibana podem ser usados nativamente para visualizar essas métricas, mas quero mostrar uma maneira nova e empolgante de fazer isso ainda mais rápido.

Recentemente, o Lens foi introduzido no Kibana como uma ferramenta mais intuitiva de visualização orientada por analistas. Este exemplo pode mostrar como o Lens pode ser usado para visualizar uma métrica do JMX customizada, coletada pelo agente.

Exemplo do Lens

Para tornar as coisas interessantes, vamos executar um comando de escalabilidade horizontal para aumentar a contagem de pods do componente petclinic, de modo que obtenhamos múltiplas linhas por JVM em execução.

$ kubectl scale --replicas=3 deployment petclinic-deployment
# Validar que a escalabilidade horizontal fez o que era para ser feito
$ kubectl get pods

Você deverá ver o seguinte:

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

Agora vem o poder do Lens:

Olha aí o Lens em ação, gente!

Barra de busca. Para buscar, claro

Obviamente, o app do Elastic APM tem uma barra de busca. Ela é ótima para procurar aquela agulha no palheiro, restringindo o escopo do problema que você está tentando avaliar. Por exemplo, veja aqui como a visualização da UI do APM pode ser restringida a um tipo específico de navegador:

O Elastic APM tem uma funcionalidade de busca poderosa porque foi desenvolvido com base no... Elasticsearch

Correlação entre traces de APM e logs

Outro exemplo útil de que o todo é mais do que a soma de suas partes é a correlação entre os traces de APM e as entradas de log que foram produzidas pelo código rastreado. Os traces de APM podem ser vinculados às entradas de log pelo campo trace.id<code>. E tudo isso acontece sem muito esforço, apenas por meio de algumas configurações simples. Primeiro, vamos ver um exemplo de tal correlação.

Vamos dar uma olhada em um trace:

Correlacione traces e logs com um clique

Esse trace nos mostra a visão da linha do tempo de como diferentes partes do código foram executadas. Agora, vamos ver quais logs foram produzidos pelo código que acabamos de rastrear. Selecionaremos Trace logs (Logs de trace) no menu Actions (Ações). Isso nos levará à UI do Logs pré-selecionando a hora em que os dados de trace foram capturados e usará o trace.id para filtrar os dados de log anotados com o mesmo trace.id:

Fluxos de log do seu trace

Detalhamento de um trace id

Obviamente, o trace.id é inerente aos traces de APM, mas como conseguimos enriquecer os dados dos logs com ele? Primeiro, como estamos usando o Agente Java do Elastic APM, usamos o recurso de correlação de log que ele implementa. Na essência, ele preenche os campos trace.id e transaction.id no mapa de contexto MDC (logback no caso do Spring Boot) do framework de logging do Java. Tudo o que é necessário é definir essa variável de ambiente no ConfigMap do petclinic petclinic/petclinic.yml:

          - name: ELASTIC_APM_ENABLE_LOG_CORRELATION
            value: "true"

Em seguida, o logging da aplicação petclinic é configurado com o logging do ECS, que enriquece as entradas de log enviadas para o Elastic Stack com campos adicionais correspondentes ao Elastic Common Schema, como log.level, transaction.id etc. Para permitir isso, incluímos a seguinte dependência no pom.xml da aplicação petclinic:

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

Há também o arquivo docker/petclinic/src/main/resources/logback-spring.xml com o logging do ECS configurado para ser escrito como JSON no 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, há a anotação no ConfigMap do petclinic ( petclinic/petclinic.yml ) que aproveita a descoberta automática dos Beats para instruir o Filebeat a analisar o JSON resultante que sai do petclinic:

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

Portanto, para permitir que essa correlação funcione, precisamos habilitar o Agente Java e o framework de logging para registrar correlações de trace. Então, podemos vincular as duas partes dos dados de observabilidade.

E aqui encerramos a série

Logs, métricas e APM... conseguimos! Nesta série de posts do blog, examinamos a instrumentação de uma aplicação para coletar seus logs, métricas e traces de APM com o Elastic Stack usando Filebeat, o Metricbeat e o APM. O tutorial também demonstra como coletar logs e métricas do Kubernetes usando os mesmos componentes. Existem componentes adicionais no ecossistema da Elastic que podem adicionar mais detalhes para completar o panorama de observabilidade do seu ambiente do Kubernetes:

  • Heartbeat — uma ótima maneira de mensurar o tempo de funcionamento e a capacidade de resposta da sua aplicação e de todo o ambiente do Kubernetes. Ele pode ser implantado fora do seu cluster, mais perto de onde seus usuários estão. O Heartbeat pode ilustrar como seus usuários veem a sua aplicação, que tipo de latência de rede e resposta eles estão observando e a quantos erros estão expostos.
  • Packetbeat — obtenha uma visão do tráfego de rede interno do cluster do Kubernetes, handshakes de certificado TLS, pesquisas de DNS etc.
  • Eu incluí uma amostra de implantação do bloco de notas do Jupyter e adicionei um bloco de notas de amostra que ilustra como você pode obter acesso aos dados brutos de observabilidade armazenados no Elasticsearch, para que você possa usá-los para fazer ciência de dados como gente grande:
    k8s-o11y-workshop/jupyter/scripts/example.ipynb
        

Fique à vontade para se tornar um colaborador no repositório do Github ou criar uma ocorrência no Github se algo não estiver funcionando como esperado.

Você pode começar a monitorar seus sistemas e infraestrutura hoje mesmo. Inscreva-se para fazer uma avaliação gratuita do Elasticsearch Service no Elastic Cloud ou baixe o Elastic Stack e hospede-o você mesmo(a). Quando ele estiver em funcionamento, monitore a disponibilidade dos seus hosts com o Elastic Uptime e instrumente as aplicações em execução nos seus hosts com o Elastic APM. Você estará no caminho certo para ter um sistema totalmente observável, completamente integrado com seu novo cluster de métricas. Se encontrar obstáculos ou tiver dúvidas, vá para os nossos fóruns de discussão — estamos aqui para ajudar.