Descomplicando o Prometheus
DAY-8
O que iremos ver hoje?
Durante o dia de hoje, nós iremos passear um pouco pelas métricas que estamos coletando do nosso cluster Kubernetes. A ideia hoje é brincar um pouco mais com PromQL para extrair o máximo de valor das métricas que estamos coletando.
Quando estamos utilizando o Kube-Prometheus, temos que saber que já temos dezenas de novas métricas que nos mostram detalhes do comportamento do nosso cluster.
Outro ponto importante do dia de hoje será conhecer um pouco mais no detalhe, onde e como podemos mudar as características do nosso Prometheus e do nosso AlertManager.
Quando instalamos o Kube-Prometheus, e por consequência o Prometheus Operator, nós estamos expandindo o Kubernetes, dando maiores poderes e funções que antes ele não tinha. Entre os novos poderes que o Kubernetes agora possui estão os recursos que já vimos, como o PodMonitor, ServiceMonitor e o PrometheusRule.
Hoje ainda iremos conhecer mais dois recursos que o Prometheus Operator nos dá, um recurso chamado Prometheus e outro chamado AlertManager. Mas não vou dar detalhes agora, somente durante o dia de hoje.
Conteúdo do Day-8
DAY-8
- Descomplicando o Prometheus
- DAY-8
- O que iremos ver hoje?
- Conteúdo do Day-8
- Vamos brincar com as métricas do Kubernetes
- Agora vamos saber se o nosso cluster está com problemas
- E como saber se meus deployments estão com problemas?
- E como saber se meus serviços estão com problemas?
- Como eu posso modificar as configurações do meu Prometheus?
- DAY-8
Vamos brincar com as métricas do Kubernetes
Muito bem, chegamos naquele momento que não precisaremos instalar mais nada, pelo menos por agora, pois já temos o nosso cluster Kubernetes com o Kube-Prometheus instalado.
O que vamos fazer agora é usufruir de todo o conhecimento já adquirido e também por todo o trabalho que já fizemos até esse momento.
Então agora é a hora de começar a brincar com as métricas e assim extrair informações sobre a saúde e performance do nosso cluster Kubernetes.
O que podemos saber sobre os nodes do nosso cluster?
Algumas métricas que podemos extrair sobre os nodes do nosso cluster são:
- Quantos nós temos no nosso cluster?
- Qual a quantidade de CPU e memória que cada nó tem?
- O nó está disponível para receber novos pods?
- Qual a quantidade de informação que cada nó está recebendo e enviando?
- Quantos pods estão rodando em cada nó?
Vamos responder essas quatro perguntas utilizando o PromQL e as métricas que estamos coletando do nosso cluster Kubernetes.
Quantos nós temos no nosso cluster?
Para responder essa pergunta, vamos utilizar a métrica kube_node_info
que nos mostra informações sobre os nós do nosso cluster. Podemos utilizar a função count
para contar quantas vezes a métrica kube_node_info
aparece no nosso cluster.
count(kube_node_info)
No nosso cluster, temos 2 nós, então a resposta para essa pergunta é 2.
Qual a quantidade de CPU e memória que cada nó tem?
Para responder essa pergunta, vamos utilizar a métrica kube_node_status_allocatable
que nos mostra a quantidade de CPU e memória que cada nó tem disponível para ser utilizado.
kube_node_status_allocatable
Aqui ele vai te trazer todas as informações sobre CPU, memória, pods, etc. Mas nós só queremos saber sobre CPU e memória, então vamos filtrar a nossa consulta para trazer apenas essas informações.
kube_node_status_allocatable{resource="cpu"}
kube_node_status_allocatable{resource="memory"}
Fácil, agora precisamos somente de um pouco de matemática para converter os valores referente a memória para gigabytes.
kube_node_status_allocatable{resource="memory"} / 1024 / 1024 / 1024
Pronto, agora ficou um pouco mais fácil de ler a quantidade de memória que temos em cada nó.
O nó está disponível para receber novos pods?
Para responder essa pergunta, vamos utilizar a métrica kube_node_status_condition
que nos mostra o status de cada nó do nosso cluster.
kube_node_status_condition{condition="Ready", status="true"}
Com a consulta acima, estamos perguntando para métrica kube_node_status_condition
se o nó está pronto para receber novos pods. Se o nó estiver pronto, ele vai retornar o valor 1, caso contrário, ele vai retornar o valor 0.
Isso porque estamos perguntando para a métrica kube_node_status_condition
se o nó está com a condição Ready
e se o status dessa condição é true
, se mudassemos o status para false
, ele iria retornar o valor 0. Simplão demais!
Qual a quantidade de informação que cada nó está recebendo e enviando?
Aqui vamos levar em consideração que estamos falando de trafego de rede, o quanto o nosso nó está recebendo e enviando de dados pela rede.
Para isso vamos utilizar a métrica node_network_receive_bytes_total
e node_network_transmit_bytes_total
que nos mostra a quantidade de bytes que o nó está recebendo e enviando.
node_network_receive_bytes_total
node_network_transmit_bytes_total
Perceba que a saída dessa consulta ela traz a quantidade de bytes por pod, mas nós queremos saber a quantidade de bytes por nó, então vamos utilizar a função sum
para somar a quantidade de bytes que cada pod está recebendo e enviando.
sum by (instance) (node_network_receive_bytes_total)
sum by (instance) (node_network_transmit_bytes_total)
Pronto, dessa forma teriamos a quantidade de bytes que cada nó está recebendo e enviando. No meu caso, como somente tenho dois nodes, o resultado foram duas linhas, uma para cada nó, mostrando a quantidade de bytes que cada nó está recebendo e enviando.
Agora vamos converter esses bytes para megabytes, para ficar mais fácil de ler.
sum by (instance) (node_network_receive_bytes_total) / 1024 / 1024
sum by (instance) (node_network_transmit_bytes_total) / 1024 / 1024
Vamos para a próxima pergunta.
Quantos pods estão rodando em cada nó?
Para responder essa pergunta, vamos utilizar a métrica kube_pod_info
que nos mostra informações sobre os pods que estão rodando no nosso cluster.
kube_pod_info
Caso eu queria saber o número de pods que estão rodando em cada nó, eu poderia utilizar a função count
para contar quantas vezes a métrica kube_pod_info
aparece em cada nó.
count by (node) (kube_pod_info)
Pronto, agora eu sei quantos pods estão rodando em cada nó. No meu caso o meu cluster está bem sussa, somente 9 pods em um nó e 10 no outro, um dia de alegriaaaaa!
Agora vamos saber se o nosso cluster está com problemas
Agora que já sabemos como extrair informações sobre a saúde e performance do nosso cluster Kubernetes, vamos aprender como podemos ser notificados caso o nosso cluster esteja com algum problema.
O que podemos saber sobre os pods do nosso cluster?
Algumas métricas que podemos extrair sobre os pods do nosso cluster são:
- Quantos pods estão rodando no nosso cluster?
- Quantos pods estão com problemas?
- Verificar os pods e os limites de memória e CPU configurados
- Verificar se o cluster está com problemas de espaço em disco
- Verificar se o cluster está com problemas de consumo de memória
Quantos pods estão rodando no nosso cluster?
Essa é fácil e já sabemos qual a métrica que vai nos ajudar a responder essa pergunta.
count(kube_pod_info)
Simples assim.
Quantos pods estão com problemas?
Para responder essa pergunta, vamos utilizar a métrica kube_pod_status_phase
que nos mostra o status de cada pod do nosso cluster.
kube_pod_status_phase
Essa métrica irá nos mostrar o status de cada pod, se o pod está rodando, se ele está em erro, se ele está em execução, etc. Mas nós só queremos saber se o pod está em erro, então vamos filtrar a nossa consulta para trazer apenas os pods que estão em erro.
kube_pod_status_phase{phase="Failed"}
E se eu quiser saber o número de pods que estão em erro?
count(kube_pod_status_phase{phase="Failed"})
Vamos melhorar, eu quero saber o número de pods que estão em erro por namespace.
count by (namespace) (kube_pod_status_phase{phase="Failed"})
Ou ainda por nó.
count by (node) (kube_pod_status_phase{phase="Failed"})
Simples assim.
Os status que podemos utilizar são:
Pending
: Pod está aguardando para ser executadoRunning
: Pod está sendo executadoSucceeded
: Pod foi executado com sucessoUnknown
: Pod está em um estado desconhecidoFailed
: Pod foi executado e falhou
Agora é só escolher o que você quer saber e sair testando.
Verificar os pods e os limites de memória e CPU configurados
Para responder essa pergunta, vamos utilizar a métrica kube_pod_container_resource_limits
que nos mostra os limites de memória e CPU que cada pod está utilizando.
kube_pod_container_resource_limits
Agora vamos filtrar a nossa consulta para trazer apenas os pods e os limites de memória e CPU configurados.
kube_pod_container_resource_limits{resource="memory"}
kube_pod_container_resource_limits{resource="cpu"}
Assim você consegue saber quais os limites de memória e CPU que cada pod está utilizando.
Verificar se o cluster está com problemas relacionados ao disco
Tem um status de node que é o DiskPressure
, que significa que o nó está com problemas relacionados ao disco. Para saber se o nó está com esse status, vamos utilizar a métrica kube_node_status_condition
que nos mostra o status de cada nó.
kube_node_status_condition{condition="DiskPressure", status="true"}
Se o valor retornado for 1, significa que o nó está com problemas relacionados ao disco, agora, se o valor for 0, significa que o nó está ok e você não precisa se preocupar.
Verificar se o cluster está com problemas relacionados a memória
Tem um status de node que é o MemoryPressure
, que significa que o nó está com problemas relacionados a memória. Para saber se o nó está com esse status, vamos utilizar a métrica kube_node_status_condition
que nos mostra o status de cada nó.
kube_node_status_condition{condition="MemoryPressure", status="true"}
Se o valor retornado for 1, se prepare, pois você vai precisar entender o que está pegando com o seu nó, ou seja, terá um dia de trabalho pela frente. :D
E como saber se meus deployments estão com problemas?
Algumas perguntas que podemos responder sobre os deployments do nosso cluster são:
- Quantos deployments estão rodando no meu cluster?
- Quantos deployments estão com problemas?
- Qual o status dos meus deployments?
Quantos deployments estão rodando no meu cluster?
Para responder essa pergunta, vamos utilizar a métrica kube_deployment_status_replicas
que nos mostra o número de replicas que cada deployment está rodando.
kube_deployment_status_replicas
Assim ele traz a lista de todos os deployments e o número de replicas que cada um está rodando.
Quantos deployments estão com problemas?
Para responder essa pergunta, vamos utilizar a métrica kube_deployment_status_replicas_unavailable
que nos mostra o número de replicas indisponíveis que cada deployment está rodando.
kube_deployment_status_replicas_unavailable
Se tudo estiver bem, o valor retornado será 0, caso contrário, o valor retornado será o número de replicas indisponíveis.
Qual o status dos meus deployments?
Para responder essa pergunta, vamos utilizar a métrica kube_deployment_status_condition
que nos mostra o status de cada deployment.
kube_deployment_status_condition
Com a consulta acima, você consegue saber o status de cada deployment, se ele está ok, se ele está com problemas, etc.
Se quisermos saber a lista de deployments com problemas, podemos utilizar a seguinte consulta.
kube_deployment_status_condition{condition="Available", status="false"}
Assim, se o valor retornado for 1, significa que o deployment está com problemas, caso contrário, significa que o deployment está ok.
E como saber se meus serviços estão com problemas?
Algumas perguntas que podemos responder sobre os serviços do nosso cluster são:
- Quantos serviços estão rodando no meu cluster?
- Todos os meus serviços estão com endpoints?
- Todos os meus serviços estão com endpoints ativos?
Vamos responder cada uma delas.
Quantos serviços estão rodando no meu cluster?
Para responder essa pergunta, vamos utilizar a métrica kube_service_info
que nos mostra o número de serviços que estão rodando no nosso cluster.
kube_service_info
Assim ele traz a lista de todos os serviços que estão rodando no nosso cluster, com o valor 1.
Todos os meus serviços estão com endpoints?
Para responder essa pergunta, vamos utilizar a métrica kube_endpoint_address
que nos traz a lista de endpoints de cada serviço.
kube_endpoint_address
Agora para saber os endpoints para um determinado serviço, vamos utilizar a seguinte consulta.
kube_endpoint_address{endpoint="kube-dns"}
Todos os meus serviços estão com endpoints ativos?
Podemos ainda buscar por endpoints com o status ready
igual a false
, o que significa que o endpoint não está ativo.
kube_endpoint_address{ready="false"}
Se a lista for vazia, significa que todos os endpoints estão ativos!
Acho que já deu para brincar um pouco sobre as nossas métricas que estão vindo do Kubernetes! :D
Vamos brincar com algo novo agora!
Como eu posso modificar as configurações do meu Prometheus?
Quando fizemos a instalação do nosso kube-prometheus, nós criamos alguns Custom Resource Definitions (CRDs) em nosso cluster. Nós já vimos alguns deles como o ServiceMonitor
e o PrometheusRule
, porém o nosso foco agora será em dois outros CRDs que são o Prometheus
e o Alertmanager
.
O Prometheus
é o nosso recurso que vai nos permitir configurar o Prometheus que está rodando em nosso cluster. Já o Alertmanager
é o nosso recurso que vai nos permitir configurar o Alertmanager.
Vamos focar nessa primeira parte no Prometheus
.
Definindo o nosso Prometheus
Como eu disse, o recurso Prometheus
é o nosso recurso que vai nos permitir configurar o Prometheus, e assim customiza-lo para as nossas necessidades.
Esse arquivo é o arquivo que vem por padrão quando instalamos o kube-prometheus, ele fica dentro do diretório manifests/
do nosso repositório do kube-prometheus e ele se chama prometheus-prometheus.yaml
.
apiVersion: monitoring.coreos.com/v1 # Versão da API
kind: Prometheus # Tipo do recurso, no caso, Prometheus
metadata: # Informações sobre o recurso
labels: # Labels que serão adicionadas ao nosso Prometheus
app.kubernetes.io/component: prometheus # Label que indica que o recurso é um Prometheus
app.kubernetes.io/instance: k8s # Label que indica que o recurso é o Prometheus do nosso cluster
app.kubernetes.io/name: prometheus # Label que indica que o recurso é um Prometheus
app.kubernetes.io/part-of: kube-prometheus # Label que indica que o recurso é parte do kube-prometheus
app.kubernetes.io/version: 2.42.0 # Label que indica a versão do Prometheus
name: k8s # Nome do nosso Prometheus
namespace: monitoring # Namespace onde o Prometheus vai ser criado
spec: # Especificações do nosso Prometheus
alerting: # Configurações de alerta
alertmanagers: # Lista de alertmanagers que o Prometheus vai utilizar
- apiVersion: v2 # Versão da API do Alertmanager
name: alertmanager-main # Nome do Alertmanager
namespace: monitoring # Namespace onde o Alertmanager está rodando
port: web # Porta que o Alertmanager está rodando
enableFeatures: [] # Lista de features que serão habilitadas no Prometheus, no caso, nenhuma
externalLabels: {} # Labels que serão adicionadas a todas as métricas que o Prometheus coletar
image: quay.io/prometheus/prometheus:v2.42.0 # Imagem do Prometheus
nodeSelector: # Node selector que será utilizado para definir em qual node o Prometheus vai rodar
kubernetes.io/os: linux # Node selector que indica que o Prometheus vai rodar em nodes com o sistema operacional Linux
podMetadata: # Metadata que será adicionada aos pods do Prometheus
labels: # Labels que serão adicionadas aos pods do Prometheus
app.kubernetes.io/component: prometheus # Label que indica que o pod é um Prometheus
app.kubernetes.io/instance: k8s # Label que indica que o pod é o Prometheus do nosso cluster
app.kubernetes.io/name: prometheus # Label que indica que o pod é um Prometheus
app.kubernetes.io/part-of: kube-prometheus # Label que indica que o pod é parte do kube-prometheus
app.kubernetes.io/version: 2.42.0 # Label que indica a versão do Prometheus
podMonitorNamespaceSelector: {} # Namespace selector que será utilizado para selecionar os pods que serão monitorados pelo Prometheus
podMonitorSelector: {} # Selector que será utilizado para selecionar os pods que serão monitorados pelo Prometheus
probeNamespaceSelector: {} # Namespace selector que será utilizado para selecionar os pods que serão monitorados pelo Prometheus
probeSelector: {} # Selector que será utilizado para selecionar os pods que serão monitorados pelo Prometheus
replicas: 2 # Número de réplicas que o Prometheus vai ter
resources: # Recursos que serão utilizados pelo Prometheus
requests: # Recursos mínimos que serão utilizados pelo Prometheus
memory: 400Mi # Memória mínima que será utilizada pelo Prometheus
ruleNamespaceSelector: {} # Namespace selector que será utilizado para selecionar as regras que serão utilizadas pelo Prometheus
ruleSelector: {} # Selector que será utilizado para selecionar as regras que serão utilizadas pelo Prometheus
securityContext: # Security context que será utilizado pelo Prometheus
fsGroup: 2000 # ID do grupo que será utilizado pelo Prometheus
runAsNonRoot: true # Indica que o Prometheus vai rodar como um usuário não root
runAsUser: 1000 # ID do usuário que será utilizado pelo Prometheus
serviceAccountName: prometheus-k8s # Nome da service account que será utilizada pelo Prometheus
serviceMonitorNamespaceSelector: {} # Namespace selector que será utilizado para selecionar os serviços que serão monitorados pelo Prometheus
serviceMonitorSelector: {} # Selector que será utilizado para selecionar os serviços que serão monitorados pelo Prometheus
version: 2.42.0 # Versão do Prometheus
Esse arquivo é o arquivo que vem por padrão quando instalamos o kube-prometheus, ele fica dentro do diretório manifests/
do nosso repositório do kube-prometheus.
No arquivo acima, eu já adicionei comentários para explicar o que cada parte do arquivo faz, espero que tenha ajudado no entendimento.
Caso você queira fazer alguma alteração no Prometheus que já está rodando, basta alterar esse arquivo e aplicar as alterações no cluster.
Vamos imaginar que você queira adicionar limites de utilização de memória e CPU no Prometheus, para isso, basta adicionar as seguintes linhas no arquivo.
resources: # Recursos que serão utilizados pelo Prometheus
requests: # Recursos mínimos que serão utilizados pelo Prometheus
memory: 400Mi # Memória mínima que será utilizada pelo Prometheus
cpu: 500m # CPU mínima que será utilizada pelo Prometheus
limits: # Recursos máximos que serão utilizados pelo Prometheus
memory: 1Gi # Memória máxima que será utilizada pelo Prometheus
cpu: 900m # CPU máxima que será utilizada pelo Prometheus
Preste atenção para adicionar esse conteúdo dentro do bloco spec:
e com a mesma indentação.
Agora, vamos aplicar as alterações no cluster.
$ kubectl apply -f prometheus.yaml
Agora, vamos verificar se o Prometheus foi atualizado.
$ kubectl get pods -n monitoring prometheus-k8s-0 -o yaml | grep -A 10 resources:
resources:
limits:
cpu: 900m
memory: 1Gi
requests:
cpu: 500m
memory: 400Mi
Como podemos ver, o Prometheus foi atualizado com os novos recursos.
Tem diversas outras configurações que podemos fazer no Prometheus, como por exemplo, adicionar regras para alertas, selectors para selecionar os pods que serão monitorados, etc.
Mas eu sugiro que você comece a testar e achar a melhor configuração para a sua necessidade. Mas lembre-se sempre, você precisa testar, você precisa explorar, você precisa aprender! Bora pra cima!
Definindo o nosso Alertmanager
Da mesma forma como fizemos com o Prometheus, vamos conhecer o arquivo responsável por definir o nosso Alertmanager.
O arquivo abaixo é o arquivo que vem por padrão quando instalamos o kube-prometheus, ele fica dentro do diretório manifests/
do nosso repositório do kube-prometheus, o nome dele é alertmanager-alertmanager.yaml
.
```yaml
apiVersion: monitoring.coreos.com/v1 # Versão da API do Alertmanager
kind: Alertmanager # Tipo do objeto que estamos criando
metadata: # Metadata do objeto que estamos criando
labels: # Labels que serão adicionadas ao objeto que estamos criando
app.kubernetes.io/component: alert-router # Label que indica que o objeto é um Alertmanager
app.kubernetes.io/instance: main # Label que indica que o objeto é o Alertmanager principal
app.kubernetes.io/name: alertmanager # Label que indica que o objeto é um Alertmanager
app.kubernetes.io/part-of: kube-prometheus # Label que indica que o objeto é parte do kube-prometheus
app.kubernetes.io/version: 0.25.0 # Label que indica a versão do Alertmanager
name: main # Nome do objeto que estamos criando
namespace: monitoring # Namespace onde o objeto que estamos criando será criado
spec: # Especificações do objeto que estamos criando
image: quay.io/prometheus/alertmanager:v0.25.0 # Imagem que será utilizada pelo Alertmanager
nodeSelector: # Selector que será utilizado para selecionar os nós que o Alertmanager vai rodar
kubernetes.io/os: linux # Selector que indica que o Alertmanager vai rodar em nós Linux
podMetadata: # Metadata que será adicionada aos pods do Alertmanager
labels: # Labels que serão adicionadas aos pods do Alertmanager
app.kubernetes.io/component: alert-router # Label que indica que o pod é um Alertmanager
app.kubernetes.io/instance: main # Label que indica que o pod é o Alertmanager principal
app.kubernetes.io/name: alertmanager # Label que indica que o pod é um Alertmanager
app.kubernetes.io/part-of: kube-prometheus # Label que indica que o pod é parte do kube-prometheus
app.kubernetes.io/version: 0.25.0 # Label que indica a versão do Alertmanager
replicas: 3 # Número de réplicas que o Alertmanager vai ter
resources: # Recursos que serão utilizados pelo Alertmanager
limits: # Recursos máximos que serão utilizados pelo Alertmanager
cpu: 100m # CPU máxima que será utilizada pelo Alertmanager
memory: 100Mi # Memória máxima que será utilizada pelo Alertmanager
requests: # Recursos mínimos que serão utilizados pelo Alertmanager
cpu: 4m # CPU mínima que será utilizada pelo Alertmanager
memory: 100Mi # Memória mínima que será utilizada pelo Alertmanager
securityContext: # Security context que será utilizado pelo Alertmanager
fsGroup: 2000 # ID do grupo que será utilizado pelo Alertmanager
runAsNonRoot: true # Indica que o Alertmanager vai rodar como um usuário não root
runAsUser: 1000 # ID do usuário que será utilizado pelo Alertmanager
serviceAccountName: alertmanager-main # Nome da service account que será utilizada pelo Alertmanager
version: 0.25.0 # Versão do Alertmanager
Adicionei também comentários para explicar o que cada parte do arquivo faz, assim fica fácil de você entender o que está acontecendo. Sempre lembrando, veja sempre a documentação oficial para entender melhor o que cada configuração faz e todas as opções que você tem.
Caso você queira fazer alguma alteração no Alertmanager que já está rodando, basta alterar esse arquivo e aplicar as alterações no cluster com o comando abaixo.
$ kubectl apply -f alertmanager-alertmanager.yaml
Pronto, seu Alertmanager foi atualizado com as novas configurações, caso você tenha feito alguma alteração. hahah :D