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.
Por último, é necessário habilitar o ClusterChecks do datadog agent, definindo spec.features.clusterChecks.enabled como true no deploy do cluster agent.
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
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
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
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
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.
Na tela da integração já temos uma parte da documentação disponível a respeito da integração via plugin do 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:
Também na documentação da integração com o rabbitMQ, ele já nos informa o seguinte:
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"
}
}
]
}
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
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
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
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:
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
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:
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
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
Top comments (1)
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.