Operação¶
Objetivo¶
Este documento descreve como a infraestrutura e os sistemas da Page Saúde devem ser operados no dia a dia. Ele serve como referência prática para manter o ambiente estável, previsível e recuperável.
Não é um manual exaustivo. O foco é registrar o que não pode ser esquecido, o que já causou problemas e o que exige atenção recorrente.
Rotinas Operacionais¶
Atividades recorrentes necessárias para a saúde do ambiente.
- Verificação geral dos serviços críticos
- Acompanhamento de alertas de monitoramento
- Validação de execução de backups
- Verificação de espaço em disco e recursos
(Detalhamento excessivo deve ser evitado; procedimentos críticos podem ser destacados abaixo.)
Monitoramento¶
Visão Geral¶
O monitoramento tem como objetivo detectar problemas antes de impactarem o negócio.
Aspectos monitorados:
- Disponibilidade de serviços
- Uso de recursos (CPU, memória, disco)
- Logs relevantes
- Alertas de falha ou degradação
Limites e Retenção¶
A stack de observabilidade foi configurada com limites estritos para uso em servidores com recursos limitados (ex: 50GB Disco).
- Retenção: 7 Dias para Logs (Loki), Traces (Tempo) e Métricas (Prometheus).
- Disco: Limites de tamanho configurados (~5GB Prometheus, 1GB Min Free Pyroscope).
Backups e Restauração¶
Visão Técnica¶
Utilizamos um serviço robusto de backup e restauração com formato binário customizado (pg_dump -Fc) e compressão Zstd.
- Formato:
YYYYMMDDHHMMSS_<dbname>.sql.zst(Custom Format). - Segurança: Restaura backups de produção ignorando owners/privilegios originais (
--no-owner --no-privileges) e limpando objetos existentes (--clean). - Automação: Detecção automática de banco de destino e criação automática (
createdb) se não existir.
Procedimentos de Execução¶
Rodar via Docker Compose na pasta services/database/postgres/backup/:
# Backup Interativo (Lista bancos disponíveis)
docker compose run --rm backup
# Backup Específico
docker compose run --rm backup pagesaude
# Restore Interativo (Lista arquivos disponíveis)
docker compose run --rm backup restore
# Restore Específico
docker compose run --rm backup restore 20240101120000_pagesaude.sql.zst
Versões da stack¶
Componentes fixados em versão (nunca latest). Pendências conhecidas de atualização:
| Componente | Versão atual | Pendência |
|---|---|---|
| PostgreSQL | 14.10 | EOL em novembro de 2026. Planejar upgrade de major com janela e teste de restore. |
O Pyroscope roda na arquitetura v2 (-architecture.storage=v2), com escrita via
segment-writer e blocos em storage local (filesystem). Object storage só seria necessário
em deploy distribuído. Os flags da linha 1.x (-storage.tsdb.*, -ingester.*) não existem
mais no 2.x — ao ajustar o compose, confira os nomes com
docker run --rm --entrypoint /usr/bin/pyroscope grafana/pyroscope:<tag> -help-all.
Os perfis antigos da v1 não são migrados: a mudança descarta o histórico de profiling.
Ao atualizar Grafana entre majors, faça backup do volume grafana-data antes: a migração
de schema é irreversível e o rollback exige restaurar esse backup.
Notificações de Alertas¶
Os alertas são avaliados pelo Prometheus e entregues ao Alertmanager (Mimir em modo
-target=alertmanager). Os canais são configurados na UI do Grafana — o repositório
não versiona webhook, senha nem destinatário.
Criar canais (Grafana → Alerting)¶
- Contact points → + Add contact point. Escolha "Mimir (oficial)" no seletor do topo, não "Grafana". O Grafana não permite alterar globalmente o padrão desse seletor.
- Crie os dois contact points abaixo. O webhook do Discord e destinatários de e-mail ficam somente na UI:
| Contact point | Integrações | Uso |
|---|---|---|
alertas-gerais |
Discord | rota padrão, P1 e P2 |
alertas-criticos |
Discord e Email | P0 |
- Notification policies → crie políticas aninhadas com matchers por
severity, apontando cada uma para o contact point desejado.
Em tenant ainda sem configuração ativa, o receiver fallback-noop aparece na UI: ele pode
ser renomeado para alertas-gerais e receber a integração Discord. O arquivo montado
permanece vazio e não ganha credenciais.
Não crie policy por owner agora: o label fica reservado para roteamento futuro, abaixo da
policy de severidade correspondente.
Sugestão de roteamento¶
| Matcher | Contact point | group_wait / repetição |
|---|---|---|
| padrão | alertas-gerais |
30 s / 4 h |
severity = p0 |
alertas-criticos |
10 s / 30 min |
severity = p1 |
alertas-gerais |
30 s / 4 h |
severity = p2 |
alertas-gerais |
5 min / 24 h |
Agrupar por alertname, service e environment.
O que já vem pronto do repositório¶
services/observability/stack/config/alertmanager.yml é o fallback imutável: traz
agrupamento, inibições e o receiver vazio fallback-noop. HostDown silencia alertas
derivados do host, banco fora do ar silencia alertas derivados do serviço e
AlloyAgentDown silencia alertas de container do host. As policies por severidade e os
contact points são criados somente na UI.
Atenção: esse arquivo só vale enquanto não houver configuração salva pela UI. Ao salvar a primeira vez, a configuração da UI substitui o fallback por completo — as inibições precisam ser recriadas na UI ou reenviadas pela API de configuração, já que a tela do Grafana não expõe
inhibit_rules.
SMTP contratado¶
O Ansible configura o SMTP do Grafana e gera o fallback do Alertmanager com
global.smtp_*. Os valores não secretos vêm das Variables do GitHub Environment
(SMTP_SMARTHOST, SMTP_FROM, SMTP_AUTH_USERNAME e SMTP_REQUIRE_TLS); a senha vem do
secret SMTP_PASSWORD, é gravada com modo 0600 e é lida pelos dois containers via
arquivo. Portanto, ela não aparece em YAML versionado, .env nem em docker inspect.
Use a mesma identidade remetente já autorizada pela aplicação. Antes de ativar, confirme SPF com um único registro, DKIM e DMARC para o domínio. Como o relay é gerenciado, não é necessário manter PTR/rDNS próprio nem liberar a porta 25 de saída; use a porta e TLS indicados pelo fornecedor.
O Grafana usa GF_SMTP_* apenas para seus próprios e-mails. O Alertmanager do Mimir usa
seu global.smtp_* e smtp_auth_password_file; é essa configuração que permite salvar o
contact point de e-mail de alertas-criticos.
Migração de configuração ativa: se a UI já salvou uma configuração, o fallback não é aplicado. Antes de criar ou editar o e-mail, exporte a configuração ativa pela API do Mimir (
mimirtool alertmanager get), acrescente o blocoglobal.smtp_*comsmtp_auth_password_file: /run/secrets/smtp_passworde reenvie preservando routes, receivers, templates e inibições (mimirtool alertmanager load). Faça backup do export antes. O Ansible não sobrescreve essa configuração para preservar as edições da UI.
Depois do provisionamento, envie uma notificação de teste do contact point
alertas-criticos; confirme a entrega no Discord e no e-mail e remova qualquer contato de
teste que não deva receber incidentes.
Health Checks externos (Cloudflare)¶
Para cada endpoint público crítico, crie um Cloudflare Health Check (Pro) HTTPS para um
/health que não exija autenticação, com código esperado 2xx. Escolha regiões e
intervalo compatíveis com o tráfego do endpoint; as mudanças de estado só são notificadas
após consenso das regiões selecionadas.
- Em Notifications → Destinations → Webhooks → Create, crie um destino do tipo Discord, cole a URL e use Save and Test. A URL do webhook é secret e fica apenas na Cloudflare.
- Em Traffic → Health Checks → Create, configure o endpoint e use Save and Deploy.
- Na página Health Checks, selecione Configure an alert, escolha os checks e o gatilho de mudança de estado, e associe o destino Discord criado anteriormente.
- Force uma resposta não-
2xxem ambiente seguro e confirme a notificação de falha e a de recuperação. Reponha o endpoint e registre o resultado.
Esse alerta é externo e complementar ao Prometheus; não cria regra, serviço ou credencial na stack local.
Referências: criar Health Check, notificações de Health Checks e destino webhook.
Publicação da documentação¶
Esta documentação (incluindo os runbooks referenciados pelos alertas) é publicada no
Cloudflare Pages, em https://docs-ops.pagesaude.com.br. O GitHub Pages não atende:
o repositório é privado e publicar Pages a partir de repositório privado exige plano
Enterprise, que não temos.
O deploy é automático pelo workflow .github/workflows/docs.yml, disparado por mudanças
em docs/ ou mkdocs.yml. Ele constrói o site com MkDocs Material em modo --strict
(link quebrado falha o build) e verifica que todo runbook citado por um alerta existe
como página publicada — se um alerta apontar para runbook inexistente, o build falha.
Configuração inicial (uma vez)¶
O projeto precisa ser criado no modo Direct Upload (sem vínculo com repositório) — é o que permite o deploy vir do GitHub Actions. O dashboard esconde essa opção atrás de Workers & Pages → Create application → Get started → Drag and drop your files; criar pela CLI é mais direto e não exige subir arquivo nenhum:
npx wrangler login
npx wrangler pages project create pagesaude-ops-docs --production-branch=main
Atenção: um projeto Direct Upload não pode ser convertido para integração Git depois. Para trocar, é preciso criar outro projeto.
Depois:
- My Profile → API Tokens → Create Token, com a permissão
Account → Cloudflare Pages → Edit. Copiar o token. - No GitHub, em Settings → Secrets and variables → Actions, criar:
CLOUDFLARE_PAGES_API_TOKEN— o token do passo anterior;CLOUDFLARE_ACCOUNT_ID— visível na barra lateral do dashboard Cloudflare.- No projeto Pages, Custom domains → Set up a custom domain →
docs-ops.pagesaude.com.br. O registro DNS é criado automaticamente por estar na mesma conta Cloudflare.
Alternativa descartada: a integração Git do Cloudflare funciona com repositório privado, mas moveria o build para a Cloudflare e tiraria do CI a checagem que garante que todo alerta aponta para um runbook existente. Por isso o deploy fica no GitHub Actions.
Restringir o acesso (recomendado)¶
Os runbooks descrevem procedimentos e nomes internos de host. Para não deixá-los públicos, proteger o domínio com Cloudflare Access (Zero Trust, gratuito até 50 usuários):
- Zero Trust → Access → Applications → Add an application → Self-hosted.
- Domínio:
docs-ops.pagesaude.com.br. - Política de permissão:
Emails ending in @pagesaude.com.br(ou lista explícita). - Método de login: One-time PIN por e-mail já resolve, sem provedor de identidade.
Quem estiver de plantão abre o link do alerta, recebe o PIN por e-mail e acessa. Vale testar esse fluxo no celular antes de considerá-lo pronto — é onde ele será usado.
Administração de banco de dados¶
O pgAdmin foi removido (nunca operou adequadamente). Se uma ferramenta de administração visual voltar a ser necessária, avaliar CloudBeaver.
Incidentes Relevantes¶
Registro sintético de incidentes que geraram aprendizado.
- (Data) — (Descrição breve do incidente) — (Ação tomada)
Incidentes recorrentes ou de alto impacto podem justificar a criação de um documento específico ou decisão técnica.
Procedimentos Importantes¶
Procedimentos que não podem depender apenas de memória ou improviso.
- Procedimento de restauração
- Procedimento de manutenção crítica
- Procedimento de contingência
(Somente o essencial deve estar aqui.)
Pontos de Atenção¶
- Dependências externas críticas
- Componentes sensíveis a falhas
- Áreas que exigem maior cuidado em mudanças