Por que usar o OpenTelemetry? Por que se preocupar em desbravar mais um domínio no universo da observabilidade? E afinal, o que é o OpenTelemetry?

Vamos conferir como a comunidade o define: o OpenTelemetry é um framework e kit de ferramentas de observabilidade desenvolvido para criar e gerenciar dados de telemetria como traces, métricas e logs. Acima de tudo, o OpenTelemetry é independente de fornecedor e ferramentas, o que significa que pode ser usado com uma ampla variedade de backends de observabilidade, incluindo ferramentas de código aberto como Jaeger e Prometheus, além de ofertas comerciais. O OpenTelemetry é um projeto da Cloud Native Computing Foundation (CNCF).

Interessante, não é? Lendo sobre a missão, visão e os valores da comunidade, tudo isso fica ainda mais legal. Mas mesmo assim, provavelmente podemos encontrar milhares de projetos de sandbox da CNCF com metas semelhantes. O que torna o OpenTelemetry, também conhecido como OTel, tão especial?

Confira como o projeto foi se desenvolvendo com o passar do tempo e quais companhias estão contribuindo ativamente para isso. Você pode saber como ele está crescendo e o que será capaz de fazer nos próximos anos.

Então, a pergunta fundamental é: por que não fazer parte disso agora mesmo?

Noções básicas sobre o Kubernetes

O objetivo desta publicação no blog não é discutir o que a maioria de nós já sabe sobre o Kubernetes, mas um pouco de contexto pode ser útil.

O Kubernetes tem a intenção de ser uma plataforma altamente disponível. Para alcançar isso, é feito para descarregar várias responsabilidades em diversos componentes dimensionáveis. Vamos conferir rapidamente o resumo da documentação oficial:

Há algumas partes móveis, que devem operar corretamente para que seus workloads também possam ser executados sem problemas. Felizmente, esses componentes expõem seus insights de desempenho de maneira detalhada, assim você tem uma perspectiva mais ampla do que está acontecendo em seu cluster. Ainda melhor, todos eles usam uma linguagem comum: o Prometheus.

Coleta de métricas em todo o cluster

Como o Kubernetes se comunica com a gente no Prometheus, por que não responder da mesma maneira? Embora isso pareça bem simples, na verdade não é.

Para começar, o Prometheus opera com base em um mecanismo pull, o que significa que você é responsável por definir de quais endpoints o Prometheus precisa para encontrar e extrair as métricas que expõe. Isso é bem desafiador, considerando que o Kubernetes é, por natureza, extremamente dinâmico, no sentido de criar e remover contêiners com rapidez.

Felizmente, o Prometheus tem uma descoberta de serviço para o Kubernetes integrada em que você pode configurar diferentes rotinas de extração para que suas instâncias do Prometheus consigam determinar onde verificar com antecedência.

E o dimensionamento?

Conforme o cluster fica cada vez maior, uma instância do Prometheus pode exigir milhares de recursos e, portanto, uma máquina gigantesca para ser executada. É melhor ter várias instâncias pequenas sendo executadas em máquinas menores. No entanto, como estamos efetuando pull das métricas, ter várias instâncias apenas significa que extrairíamos os mesmos endpoints diversas vezes.

Considerando tudo isso, agora é um bom momento para apresentar o OpenTelemetry Collector. Resumindo brevemente, o OTel Collector consiste em três componentes principais: receptores, processadores e exportadores. Ao usar vários pontos desses três componentes, você pode criar diversos pipelines para lidar com os dados de telemetria e enviá-los para diferentes backends conforme suas necessidades.

Como podemos aproveitar o OTel Collector para falar como o Kubernetes?

Ele vem com um receptor do Prometheus, que podemos configurar assim como um servidor do Prometheus, ou seja, podemos simplesmente usar as mesmas definições de rotina de extração. O interessante é que não é necessário armazenar as métricas coletadas localmente, além da própria memória. Você pode pensar nisso como o Prometheus em modo de agente.

Até agora tudo bem. Porém, o problema com o shard permanece: ainda não conseguimos dimensionar horizontalmente nossos coletores de OTel. É aí que entra o Target Allocator. O Target Allocator fica na frente dos coletores de OTel com monitoração de estado e manipula as configurações do Prometheus deles, dependendo dos destinos a serem extraídos, por meio de sua distribuição entre as instâncias. Cada endpoint é extraído por uma instância do OTel Collector por vez. Para saber mais sobre como funciona o dimensionamento da extração, consulte a documentação oficial.

Falamos bastante sobre como o Prometheus funciona, como aproveitar os coletores de OTel e dimensioná-los, embora não tenhamos abordado o que queremos coletar. Vamos conferir o que o Kubernetes tem a oferecer.

Primeiramente, cada componente do painel de controle é exposto em suas portas dedicadas e nos fornece suas métricas no endpoint /metrics. Por exemplo, vamos analisar a configuração de uma rotina de extração do kube-api-server:

scrape_configs:
- job_name: 'kubernetes-apiservers'
  scrape_interval: 60s
  kubernetes_sd_configs:
    - role: endpoints
  scheme: https
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: default;kubernetes;https

Depois, precisamos ter visibilidade das máquinas (nós). Um produto popular e maduro para coleta e exposição de métricas de nós é o Node Exporter. Podemos executá-lo como um daemonset em cada nó (Linux) e extrair o que coleta da máquina subjacente da seguinte maneira:

scrape_configs:
- job_name: 'kubernetes-node-exporter'
  scrape_interval: 60s
  honor_labels: true
  kubernetes_sd_configs:
    - role: endpoints
  relabel_configs:
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
      action: drop
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      action: replace
      target_label: __scheme__
      regex: (https?)
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
    - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__
      regex: (.+?)(?::\d+)?;(\d+)
      replacement: $$1:$$2
    - source_labels: [__meta_kubernetes_service_name]
      action: keep
      regex: <NODE_EXPORTER_SERVICE_NAME>
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: namespace
    - source_labels: [__meta_kubernetes_service_name]
      action: replace
      target_label: service
    - source_labels: [__meta_kubernetes_pod_node_name]
      action: replace
      target_label: node

Agora que temos as métricas no nível da máquina, podemos subir um degrau para monitorar nossos contêiners. As métricas de contêiner são coletadas pela ferramenta cAdvisor (Container Advisor), que é executada em todos os nós. Podemos extraí-las da seguinte maneira:

scrape_configs:
- job_name: 'kubernetes-nodes-cadvisor'
  scrape_interval: 60s
  scheme: https
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  kubernetes_sd_configs:
    - role: node
  relabel_configs:
    - target_label: __address__
      replacement: kubernetes.default.svc:443
    - source_labels: [__meta_kubernetes_node_name]
      regex: (.+)
      target_label: __metrics_path__
      replacement: /api/v1/nodes/$$1/proxy/metrics/cadvisor

Por fim, mas não menos importante, agora precisamos saber o estado dos componentes no cluster. A ferramenta kube-state-metrics consulta vários endpoints em busca dessa informação e gera métricas, que podemos mais uma vez extrair com o receptor do Prometheus dos nossos coletores de OTel:

scrape_configs:
- job_name: 'kubernetes-kube-state-metrics'
  scrape_interval: 60s
  honor_labels: true
  kubernetes_sd_configs:
    - role: endpoints
  relabel_configs:
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
      action: drop
      regex: true
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      action: replace
      target_label: __scheme__
      regex: (https?)
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
    - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__
      regex: (.+?)(?::\d+)?;(\d+)
      replacement: $$1:$$2
    - source_labels: [__meta_kubernetes_service_name]
      action: keep
      regex: <KUBE_STATE_METRICS_SERVICE_NAME>
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: namespace
    - source_labels: [__meta_kubernetes_service_name]
      action: replace
      target_label: service
    - source_labels: [__meta_kubernetes_pod_node_name]
      action: replace
      target_label: node

Neste ponto, não é necessário dizer que podemos simplesmente criar uma rotina de extração dedicada para cada um dos componentes que queremos monitorar.

O que mais podemos conseguir do cluster?

Além das métricas que coletamos com êxito com o receptor do Prometheus, também podemos coletar eventos e logs dos clusters. (Observação: traces não serão abordados nesta publicação.)

Vamos começas pelos eventos. O Kubernetes dispara eventos sempre que uma criação, exclusão ou mutação acontece no cluster. Esses eventos podem ser buscados consultando o kube-api-server. Ainda bem que o OTel Collector tem um receptor para isso: o k8sevents. (Observação: atualmente há uma discussão para preterir esse receptor e usar o k8sobject no futuro.)

Você pode executar uma única instância do coletor para buscar os eventos do Kubernetes e encaminhá-los para a New Relic como logs. Atenção: várias instâncias do receptor k8sevent buscarão e enviarão os mesmos eventos para a New Relic.

E os logs? O OTel Collector inclui um receptor filelog, que você pode executar como um daemonset e montar o diretório de logs do nó para ele. Você pode usar várias expressões regulares (regex) para coletar, analisar, filtrar e enriquecer os logs de qualquer componente no cluster.

Implantação de coletores de OTel e monitoramento com a New Relic

Sabemos onde encontrar os dados de telemetria necessários e como coletá-los. Agora precisamos:

  1. Criar uma estratégia para implantar as instâncias do OTel Collector com as configurações necessárias.
  2. Criar dashboards e alertas adequados com consultas abrangentes da New Relic Query Language (NRQL) para monitorar os clusters.

Boas notícias! Há um repositório que contém tudo o que abordamos até aqui:

  • Um chart público do Helm que você pode usar para implementar os coletores de OTel.
  • Uma implantação do Terraform que você pode usar para inicializar um monitoramento predefinido na sua conta da New Relic.

Para obter mais informações, confira os seguintes recursos:

  • Leia esta documentação para entender por que precisamos de vários tipos (daemonset, deployment, statefulset, singleton) de coletores.
  • Consulte esta documentação para implantar a solução de monitoramento em seu cluster.
  • Saiba como consultar de maneira adequada e entender os dados do Prometheus coletados conforme esta documentação.

Consulte esta documentação para criar dashboards e alertas em sua conta da New Relic.