DEV Community

Cover image for Monitorando RabbitMQ implantado no Kubernetes como Cluster Operator com Datadog Autodiscovery
Ewerton Henrique Marschalk
Ewerton Henrique Marschalk

Posted on

Monitorando RabbitMQ implantado no Kubernetes como Cluster Operator com Datadog Autodiscovery

Introdução

Atualmente temos duas maneiras de realizar o monitoramento de clusters RabbitMQ, via Management Plugin e via OpenMetricsV2 (Prometheus Plugin).

Via management Plugin, realizamos queries diretamente na API do RabbitMQ (via Rabbitmq CLI), sendo assim necessitamos de criação de usuários com permissão para realizar as queries, o que adiciona etapas extras para reproduzir em larga escala, além de ser mais custoso em questão de performance do cluster.

Via OpenMetricsV2, a partir da versão 3.8 do RabbitMQ ele já vem pronto para ser monitorado, não necessitando de nenhuma configuração extra na parte do Rabbit.

Porém se você tentou seguir a documentação do datadog a respeito da integração, deve ter notado que ela é um pouco vaga e omissa em diversos pontos, nesse tópico vou demonstrar um passo a passo como realizar o deploy do rabbit via Cluster Operator em um cluster kubernetes, e monitorar as filas e consumers via datadog.

Pré-requisitos

Nessa documentação não vou abordar tópicos sobre como subir um Cluster Kubernetes e nem sobre como Instalar o Datadog Cluster Agent. Ela parte do princípio de que você já tenha isso rodando no seu ambiente.
O cluster operator do RabbitMQ solicita que o Kubernetes esteja na versão 1.19 ou superior.
Para o Datadog Autodiscovery funcionar com o rabbitMQ, você vai precisar do datadog agent 7.42 ou superior rodando no seu cluster, pois só a partir dela que temos o suporte do RabbitMQ Prometheus Metris.

rabbitmq release notes

Por último, é necessário habilitar o ClusterChecks do datadog agent, definindo spec.features.clusterChecks.enabled como true no deploy do cluster agent.

datadog documentation

Deploy do RabbitMQ Cluster Operator

Vamos usar de base o exemplo hello-world disponibilizado no repositório do RabbitMQ Cluster Operator:

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: hello-world
Enter fullscreen mode Exit fullscreen mode

Primeira coisa que vou fazer é alterar o nome de hello-world para rabbitmq, e especificar que ele vai subir no namespace rabbitmq.
Também no campo spec vou dizer que eu quero que meu serviço seja do tipo NodePort, definir que meu rabbitmq suba com 3 réplicas, definir os resources de cada replica e definir qual imagem docker eu quero que essas replicas rodem para ter mais controle sobe a versão do rabbitmq que estou rodando (além de permitir usar imagens personalizadas futuramente se eu quiser por exemplo adicionar um plugin de terceiros dentro dela):

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmq
  namespace: rabbitmq
spec:
  service:
    type: NodePort
  replicas: 3
  image: rabbitmq:3.11-management
  resources:
    limits:
      cpu: 500m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
Enter fullscreen mode Exit fullscreen mode

Como definimos que o nosso serviço é do tipo NodePort, toda vez que um deploy rodar vai ser atribuído uma porta aleatória para o nosso NodePort, em ambinetes produtivos precisamos pelo menos garantir que essa porta nunca mude, podemos fazer isso usando a tag override. Vou criar um override para sobrescrever o yaml do cluster operator e fixar a nodePort do rabbitmq para 30672:

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmq
  namespace: rabbitmq
spec:
  service:
    type: NodePort
  replicas: 3
  image: rabbitmq:3.11-management
  resources:
    limits:
      cpu: 500m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
  override:
    service:
      spec:
        ports:
        - name: tcp-amqp
          protocol: TCP
          port: 5672
          targetPort: 5672
          nodePort: 30672
Enter fullscreen mode Exit fullscreen mode

Por último vou adicionar alguns plugins extras e configurar o log level do rabbit como critical para não gerar logs desnecessários, para essas configurações específicas do rabbitmq existem tags personalizadas do próprio operator.

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmq
  namespace: rabbitmq
spec:
  service:
    type: NodePort
  replicas: 3
  image: rabbitmq:3.11-management
  resources:
    limits:
      cpu: 500m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
  override:
    service:
      spec:
        ports:
        - name: tcp-amqp
          protocol: TCP
          port: 5672
          targetPort: 5672
          nodePort: 30672
  rabbitmq:
    additionalConfig: |
      log.default.level = critical
    additionalPlugins:
    - rabbitmq_peer_discovery_k8s
    - rabbitmq_prometheus
    - rabbitmq_management
Enter fullscreen mode Exit fullscreen mode

Agora basta salvar nosso yaml, vou salvar como "rabbitmq.yml", e aplicar utilizando o comando kubectl apply -f rabbitmq.yml para subir um rabbit no cluster kubernetes.

Habilitando a integração com datadog

A primeira coisa que precisamos fazer é acessar a integração com rabbitmq no datadog, e clicar em instalar para habilitar o plugin.

rabbitmq integration

Na tela da integração já temos uma parte da documentação disponível a respeito da integração via plugin do prometheus:

documentação integração rabbitmq prometheus

Aqui explica como habilitar o scraping do endpoint /metrics,
que nos trás métricas agregadas, ou seja, sem dividir por queue ou vhost, se eu quiser ver status só de uma fila, preciso pegar métricas não agregadas pelo endpoint detailed.

A documentação cita que é possível fazer o scraping do /metrics/detailed, mas até o dia dessa publicação não explica como (Criei um Pull Request lá no repositório da integração adicionando um exemplo, talvez quando vocês esteja lendo esse artigo já tenha sido feito o merge e a documentação esteja mais completa).

Para entender como fazer scraping do /metrics/detailed, atualmente você precisa compreender como esse endpoint funciona e quais parâmetros ele precisa receber, e também precisa dar uma lida no código fonte da integração

Configurando o scraping de métricas agregadas

Como vimos, o rabbitmq disponibiliza dois endpoints de métricas, sendo eles um para métricas agregadas e um desagregadas,
para começar, vamos configurar o scraping do endpoint /metrics e coletar as métricas agregadas.
Para isso precisamos adicionar uma anotação no nosso deploy do RabbitMQ dizendo qual plugin utilizar e qual a url base, aqui um modelo disponibilizado na documentação sobre os autodiscoverys:
integration yaml example
Também na documentação da integração com o rabbitMQ, ele já nos informa o seguinte:
documentação datadog
Juntando essas duas informações, então sabemos que nosso annotation tem que ficar da seguinte forma:

  annotations:
    ad.datadoghq.com/rabbitmq.checks: |
      {
        "rabbitmq": {
          "init_config": {},
          "instances": [
            {
              "prometheus_plugin": { 
                "url": "http://%%host%%:15692"
               }
             }
           ]
         }
Enter fullscreen mode Exit fullscreen mode

Esse annotation tem que ser adicionado nos Pods que rodam nosso RabbitMQ, como o stateful-set do RabbitMQ é criado via cluster Operator, precisamos adicionar isso via override no yaml do cluster operator, da seguinte forma:

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmq
  namespace: rabbitmq
spec:
  service:
    type: NodePort
  replicas: 3
  image: rabbitmq:3.11-management
  resources:
    limits:
      cpu: 500m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
  override:
    service:
      spec:
        ports:
        - name: tcp-amqp
          protocol: TCP
          port: 5672
          targetPort: 5672
          nodePort: 30672
    statefulSet:
      spec:
        template:
          metadata:
            annotations:
              ad.datadoghq.com/rabbitmq.checks: |
                {
                  "rabbitmq": {
                    "init_config": {},
                    "instances": [
                        {
                          "prometheus_plugin": { 
                            "url": "http://%%host%%:15692"
                          }
                        }
                    ]
                  }
                }              
  rabbitmq:
    additionalConfig: |
      log.default.level = critical
    additionalPlugins:
    - rabbitmq_peer_discovery_k8s
    - rabbitmq_prometheus
    - rabbitmq_management
Enter fullscreen mode Exit fullscreen mode

Após realizar um kubectl apply desse yaml, os pods vão ser recriados e subir com essas annotations, a partir daí o datadog já vai começar a coletar as métricas agregadas.

Prometheus endpoint: /metrics/detailed

Para métricas desagregadas precisamos utilizar o endpoint /metrics/detailed

documentação rabbitmq retirado da documentação.

Conforme cita na documentação, o endpoint por padrão não retorna nada, você tem que passar parâmetros para dizer o que quer retornar.

Você pode passar o parâmetro "vhost=nome_do_vhost" caso queira filtrar apenas métricas de um vhost específico, ou pode não filtrar por vhost caso queira coletar dados de todos os vhosts.

Você deve passar quais os grupos de métricas quer coletar no campo "family", na documentação ele cita as "Generic metrics", que são metricas agregadas mesmo no endpoint detailed, essas a gente já consegue coletar no endpoint /metrics, o que nos interessa aqui são as Queue metrics

queue metrics

Dessas podemos começar com as duas primeiras, queue_coarse_metrics e queue_consumer_count, que já vão nos trazer quantidades de mensagem por tipo, fila e vhost, e quantidade de consumidores nessas filas:

queue metrics

Então nosso query final vai ficar:
%%host%%:15692/metrics/detailed?family=queue_coarse_metrics&family=queue_consumer_count

onde %%host%% é um Autodiscovery Template Variable, e a porta 15692 é a porta padrão do plugin do prometheus do rabbitmq.

coletando métricas desagregadas com o Datadog

datadog documentation

A documentação do datadog cita que é possível coletar essas métricas, mas não trás nenhum exemplo de como, para entender como precisamos ler o código fonte do plugin de integração, mais especificamente este arquivo:
integration plugin source code
Aqui podemos ver na linha 13 onde ele pega o campo url que definimos lá no annotation, e utiliza ele como base_url, na linha 16 da mesma maneira ele coleta um campo unaggregated_endpoint e seta na variável unagg_ep.

Agora sabemos que o nome do campo que temos que passar lá no annotations é unaggregated_endpoint, apenas precisamos entender melhor como esse valor é usado para definir o formato correto.

Podemos ver na linha 20, que o valor desse campo é juntado com a string /metrics/, então sabemos que não precisa passar o /metrics/ pois ele já é inserido via código.

Por fim, ele é adicionado ao array endpoints, e esse array é utilizado na linha 27 sendo adicionado á url base.

Sendo assim, esse valor recebe apenas o que fica pra frente do
/metrics/ do nosso query, ficando:
"unaggregated_endpoint":"detailed?family=queue_coarse_metrics&family=queue_consumer_count"

Agora basta adicionarmos esse campo no nosso annotation da seguinte forma:

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: rabbitmq
  namespace: rabbitmq
spec:
  service:
    type: NodePort
  replicas: 3
  image: rabbitmq:3.11-management
  resources:
    limits:
      cpu: 500m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
  override:
    service:
      spec:
        ports:
        - name: tcp-amqp
          protocol: TCP
          port: 5672
          targetPort: 5672
          nodePort: 30672
    statefulSet:
      spec:
        template:
          metadata:
            annotations:
              ad.datadoghq.com/rabbitmq.checks: |
                {
                  "rabbitmq": {
                    "init_config": {},
                    "instances": [
                        {
                          "prometheus_plugin": { 
                            "url": "http://%%host%%:15692",
                            "unaggregated_endpoint":"detailed?family=queue_coarse_metrics&family=queue_consumer_count"
                          }
                        }
                    ]
                  }
                }              
  rabbitmq:
    additionalConfig: |
      log.default.level = critical
    additionalPlugins:
    - rabbitmq_peer_discovery_k8s
    - rabbitmq_prometheus
    - rabbitmq_management
Enter fullscreen mode Exit fullscreen mode

Realizar um novo deploy com o comando kubectl apply -f rabbitmq.yaml
E esperar o datadog começar a coletar as métricas separadas por queue e vhost.

Pode ver as métricas que estão disponíveis nessa documentação:
https://www.rabbitmq.com/prometheus.html#detailed-endpoint

Ou pode ir no datadog em Metrics > Summary e filtrar pela tag: "kube_app_name: rabbitmq"

Tem também o dashboard padrão de RabbitMQ OpenMetrics que já vem com a integração:
https://app.datadoghq.com/dash/integration/37/rabbitmq-overview-openmetrics-version

dashboard

Top comments (1)

Collapse
 
katianomarcio profile image
Katiano Marcio Da Silva • Edited

Simplesmente lindo e eficiente! Concerteza vai ajudar a muita gente nessa nova fase Rabbit+prometheus+datadog. Parabéns pelo artigo nobre Ewerton, ficou altamente claro e rico de detalhes.