165 lines
8.8 KiB
YAML
165 lines
8.8 KiB
YAML
# =============================================================================
|
|
# Regras de alerta do Athletic Map.
|
|
#
|
|
# ── LIMITE QUE VALE SABER (2026-09-20) ──────────────────────────────────────
|
|
# O cluster NAO tem Alertmanager: estas regras DISPARAM no Prometheus (aparecem
|
|
# em Alerts, e no Grafana), mas ninguem e avisado por e-mail ou mensagem. Enquanto
|
|
# o Alertmanager nao existir, alerta so e visto por quem abre a tela. Esta
|
|
# registrado no diario como pendencia propria.
|
|
# =============================================================================
|
|
apiVersion: monitoring.coreos.com/v1
|
|
kind: PrometheusRule
|
|
metadata:
|
|
name: athleticmap-rules
|
|
namespace: monitoring
|
|
labels:
|
|
release: monitoring # o Prometheus so carrega regras com este label
|
|
spec:
|
|
groups:
|
|
- name: athleticmap.backup
|
|
rules:
|
|
# 26h: o backup roda 1x por dia (02:00 nos tenants, 02:30 no compartilhado).
|
|
# Duas horas de folga evitam alarme por atraso de agendamento.
|
|
#
|
|
# O `pg-backup.*` cobre os DOIS: o `pg-backup` de cada tenant (que ainda
|
|
# salva o Postgres antigo dele) e o `pg-backup-compartilhado`, que salva
|
|
# os bancos `athleticmap_*` da instancia compartilhada. Antes a regra
|
|
# citava `cronjob="pg-backup"` e o compartilhado — o backup dos tres
|
|
# tenants migrados — ficava SEM vigilancia nenhuma.
|
|
- alert: AthleticMapBackupStale
|
|
expr: time() - kube_cronjob_status_last_successful_time{cronjob=~"pg-backup.*"} > 93600
|
|
for: 15m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "Backup {{ $labels.cronjob }} ({{ $labels.namespace }}) sem sucesso ha mais de 26h"
|
|
description: "Ver: kubectl -n {{ $labels.namespace }} get job -l job-name --sort-by=.metadata.creationTimestamp"
|
|
|
|
# CronJob que existe e NUNCA teve uma execucao bem-sucedida. A regra
|
|
# acima nao pega este caso: sem sucesso nenhum, a metrica nem existe.
|
|
# Foi o que aconteceu com o compartilhado em 2026-09-19 (a 1a copia
|
|
# falhou por senha com quebra de linha, e o script disse "PUBLICADO").
|
|
- alert: AthleticMapBackupNuncaRodou
|
|
expr: |
|
|
kube_cronjob_spec_suspend{cronjob=~"pg-backup.*"} == 0
|
|
unless on (namespace, cronjob) kube_cronjob_status_last_successful_time
|
|
for: 6h
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "Backup {{ $labels.cronjob }} ({{ $labels.namespace }}) NUNCA rodou com sucesso"
|
|
description: "Backup que nunca rodou nao e backup. Rode a copia na hora e veja o log do Job."
|
|
|
|
# Job de backup que terminou em falha (inclusive a `primeira-rodada` que
|
|
# os scripts criam). `kube_job_status_failed` conta tentativas falhas.
|
|
- alert: AthleticMapBackupJobFalhou
|
|
expr: kube_job_status_failed{job_name=~"pg-backup.*|primeira-rodada.*"} > 0
|
|
for: 5m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "Job de backup {{ $labels.job_name }} ({{ $labels.namespace }}) falhou"
|
|
description: "kubectl -n {{ $labels.namespace }} logs job/{{ $labels.job_name }}"
|
|
|
|
- name: athleticmap.health
|
|
rules:
|
|
# O `unless` tira os pods de Job que TERMINARAM: pod concluido nao e
|
|
# "Ready", e sem isso todo backup bem-sucedido acendia um alerta
|
|
# (conferido em 2026-09-20 contra o Prometheus: a versao antiga casava
|
|
# com os pods do `pg-backup` do dia).
|
|
- alert: AthleticMapTenantPodNotReady
|
|
expr: |
|
|
kube_pod_status_ready{namespace=~".*-prod", condition="true"} == 0
|
|
unless on (namespace, pod) kube_pod_status_phase{phase=~"Succeeded|Failed"} == 1
|
|
for: 10m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "Pod {{ $labels.pod }} em {{ $labels.namespace }} nao-Ready ha mais de 10m"
|
|
description: "Comece pelo motivo, que costuma estar no evento e nao no log: kubectl -n {{ $labels.namespace }} describe pod {{ $labels.pod }} | tail -20. CrashLoop com imagem recem-trocada e quase sempre a subida do Spring — veja kubectl logs --previous."
|
|
|
|
# O no e UNICO e tem limite de 110 pods. Em 2026-09-19 a consolidacao
|
|
# parou porque nao havia vaga ("Too many pods"), e o sintoma so aparecia
|
|
# no evento do pod Pending. 95% = 104 pods.
|
|
- alert: AthleticMapNoQuaseSemVagaDePod
|
|
expr: |
|
|
sum(kube_pod_status_phase{phase=~"Running|Pending"})
|
|
/ sum(kube_node_status_allocatable{resource="pods"}) > 0.95
|
|
for: 15m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "O no esta com mais de 95% das vagas de pod ocupadas"
|
|
description: "Subir algo 'ao lado' pode ficar Pending. Consolidar tenants libera 10 vagas cada."
|
|
|
|
- name: athleticmap.provisionamento
|
|
rules:
|
|
# O teto de execucoes por hora existe porque o provisionamento IMPLANTA:
|
|
# um pedido que volta para a fila viraria um laco que publica tenant atras
|
|
# de tenant. Quando ele segura pedidos, o log registrava e mais nada — "um
|
|
# laco as tres da manha enche o log e ninguem ve".
|
|
- alert: AthleticMapProvisionamentoTetoAtingido
|
|
expr: increase(atm_provisionamento_teto_atingido_total[15m]) > 0
|
|
for: 0m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "O teto de provisionamentos por hora segurou pedidos"
|
|
description: "Ou entraram muitos clientes de uma vez, ou ha um laco. Veja provisionamento/execucao no banco do plataforma."
|
|
|
|
# P5.8 — o pedido que FALHOU. Esta e a regra que faltava, e a que a tela
|
|
# de espera pressupoe: ela diz ao cliente "nossa equipe ja foi avisada", e
|
|
# ate 2026-09-21 ninguem era avisado de nada.
|
|
#
|
|
# `> 0` e nao um patamar: cada falha e um cliente que pagou e esta olhando
|
|
# a tela de espera. Nao existe volume aceitavel disto.
|
|
#
|
|
# 10m (e nao 15m como as de cima) porque aqui alguem espera do outro lado.
|
|
- alert: AthleticMapProvisionamentoFalhou
|
|
expr: increase(atm_provisionamento_falhou_total[10m]) > 0
|
|
for: 0m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "Provisionamento falhou — ha cliente pago esperando tenant"
|
|
description: "Veja a execucao e a etapa: kubectl -n plataforma-prod exec deploy/pg-compartilhado -- psql -U postgres -d athleticmap -c \"select * from captacao.execucao_provisionamento where situacao='FALHOU' order by criado_em desc limit 5\""
|
|
|
|
# Execucao que EXPIROU e diferente de falhar: ninguem devolveu a posse —
|
|
# tipicamente o pod morreu no meio. O pedido volta para a fila sozinho, e
|
|
# por isso e warning; mas expiracao repetida quer dizer que algo mata o pod
|
|
# sempre no mesmo ponto, e ai a fila anda para tras.
|
|
- alert: AthleticMapProvisionamentoExpirou
|
|
expr: increase(atm_provisionamento_expirou_total[1h]) > 2
|
|
for: 0m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "Tres ou mais execucoes de provisionamento expiraram em 1h"
|
|
description: "A posse venceu sem o dono devolver: o pod morreu no meio da etapa. Veja restarts em kubectl -n plataforma-prod get pods -l app=servico-captacao."
|
|
|
|
# Webhook recusado e evento que o Asaas mandou e nos rejeitamos: token
|
|
# errado (configuracao) ou alguem batendo na rota (tentativa). Um ou outro
|
|
# acontece; uma rajada, nao.
|
|
- alert: AthleticMapWebhookAssinaturaRecusado
|
|
expr: increase(atm_webhook_assinatura_recusado_total[15m]) > 5
|
|
for: 0m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "Mais de 5 eventos de assinatura recusados em 15 min"
|
|
description: "Token do webhook trocado sem atualizar o SealedSecret, ou alguem batendo na rota publica."
|
|
|
|
- name: athleticmap.banco
|
|
rules:
|
|
# O Postgres compartilhado e o PgBouncer atendem TRES tenants: parada
|
|
# neles nao e incidente de um cliente, e de todos.
|
|
- alert: AthleticMapCompartilhadoFora
|
|
expr: kube_deployment_status_replicas_available{namespace="plataforma-prod",
|
|
deployment=~"pg-compartilhado|pgbouncer"} < 1
|
|
for: 5m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "{{ $labels.deployment }} sem replica disponivel — demo, piloto e acme dependem dele"
|
|
description: "Os tres tenants migrados param juntos. kubectl -n plataforma-prod get pods -l app={{ $labels.deployment }} e, se for o PgBouncer, lembre que a userlist e montada por subPath e so entra em vigor com restart."
|