Files
athletic-map-deploy/platform/monitoring/athleticmap-rules.yaml
T

133 lines
6.6 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"
# 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."
# 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"