Provisionamento e Deploy (CI/CD)¶
A infraestrutura é provisionada via GitHub Actions (.github/workflows/provision.yml) ou Ansible diretamente.
Estrutura do Ansible¶
Os componentes são organizados em roles do Ansible:
core(Base e Docker)web(Traefik/Proxy)database(PostgreSQL)cache(Redis)monitoring(Grafana Stack + Agentes)operations(Portainer)
Configuração de Ambiente¶
1. GitHub Environment¶
Para provisionamentos remotos, configure estes valores no GitHub Environment alvo como Secrets. O workflow os injeta no Ansible conforme indicado.
| Secret | Destino | Descrição |
|---|---|---|
DEFAULT_ADMIN_PASSWORD |
default_admin_password |
Senha unificada de Traefik, Grafana e Portainer. |
POSTGRES_PASSWORD |
input_postgres_password → postgres_password |
Senha do usuário PostgreSQL provisionado. |
REDIS_PASSWORD |
input_redis_password → redis_password |
Senha do Redis. |
CF_DNS_API_TOKEN |
cf_dns_api_token |
Token Cloudflare usado no DNS Challenge do Traefik. |
SMTP_PASSWORD |
Variável de ambiente do processo Ansible | Senha do relay; é gravada no secret com modo 0600. |
SSH_PRIVATE_KEY |
~/.ssh/page-ed25519 no runner |
Chave usada pelo workflow para acessar os hosts; não é uma variável Ansible. |
Nota: o usuário administrativo padrão é definido por admin_user (padrão: pageops).
Os parâmetros não secretos do relay SMTP ficam nas Variables do mesmo GitHub Environment:
| Variable | Variável Ansible | Obrigatória |
|---|---|---|
SMTP_SMARTHOST |
smtp_smarthost |
Somente para habilitar SMTP. |
SMTP_FROM |
smtp_from |
Sim, quando SMTP_SMARTHOST estiver definida. |
SMTP_AUTH_USERNAME |
smtp_auth_username |
Sim, quando SMTP_SMARTHOST estiver definida. |
SMTP_REQUIRE_TLS |
smtp_require_tls |
Não; o workflow usa true por padrão. |
Não coloque SMTP_PASSWORD em Variable, inventário ou .env.
2. Seleção de Ambiente¶
No GitHub Actions, o ambiente (staging, production ou ops) é selecionado ao disparar o workflow (inputs.environment).
Localmente, ./provision lê POSTGRES_PASSWORD, REDIS_PASSWORD e
DEFAULT_ADMIN_PASSWORD de .env.local (criado a partir de .env.example). As demais
variáveis de processo aceitas são:
| Variável | Uso |
|---|---|
SMTP_PASSWORD |
Senha do relay; forneça no ambiente do processo, nunca em .env. |
CF_DNS_API_TOKEN |
Token do DNS Challenge. Sem ele, o script usa um valor simulado, inadequado para certificados reais. |
SSH_KEY_PATH |
Caminho alternativo para a chave SSH; o padrão é ~/.ssh/page-ed25519. |
DOCKER_HOST |
Socket ou host Docker; no ambiente local é detectado automaticamente quando possível. |
ANSIBLE_LOCAL_TEMP |
Diretório temporário do Ansible; o padrão é .ansible/tmp no repositório. |
Para SMTP local, passe também os parâmetros não secretos como extra-vars, pois
SMTP_SMARTHOST, SMTP_FROM, SMTP_AUTH_USERNAME e SMTP_REQUIRE_TLS são variáveis
Ansible, não variáveis de ambiente lidas pelo script:
export CF_DNS_API_TOKEN='seu-token-aqui'
SMTP_PASSWORD='senha-do-relay' ./provision local \
-e 'smtp_smarthost=smtp.exemplo.com:587' \
-e 'smtp_from=alertas@exemplo.com' \
-e 'smtp_auth_username=alertas@exemplo.com'
# Ou para provisionar apenas servidores de AI
SSH_KEY_PATH=/caminho/para/outra-chave ./provision production --servers=ai
Tuning de Banco de Dados¶
Os parâmetros de tuning são definidos em ansible/roles/database/defaults/main.yml e sobrescritos nos inventários por ambiente.
| Variável | Descrição | Staging (2 VCPU/4GB) | Prod (8 VCPU/16GB) |
|---|---|---|---|
pg_cpus |
Limite de CPU | 1.0 |
4.0 |
pg_memory_limit |
Limite de RAM container | 1536m |
10240m |
pg_shared_buffers |
Shared Buffers | 512MB |
4GB |
pg_effective_cache_size |
Cache Size | 1536MB |
10GB |
pg_work_mem |
Work Memory | 4MB |
16MB |
pg_maintenance_work_mem |
Maintenance Work Mem | 128MB |
512MB |
pg_max_connections |
Máximo de Conexões | 100 |
300 |
pg_max_workers |
Worker Processes | 2 |
4 |
pg_max_parallel_workers |
Parallel Workers | 1 |
2 |
[!NOTE] O PgBouncer é configurado automaticamente com base em
pg_max_connectionsvia template Ansible.
Variáveis de Controle¶
Flags por Host (Inventário)¶
Estas variáveis são definidas por host no inventário Ansible e controlam quais serviços são provisionados:
| Variável | Descrição | Padrão |
|---|---|---|
with_traefik |
Provisionar Traefik (proxy/loadbalancer) | false |
with_postgres |
Provisionar PostgreSQL + PgBouncer | false |
with_redis |
Provisionar Redis | false |
with_apps |
Criar estrutura base para deploy de aplicações em apps/ |
false |
with_monitoring_stack |
Provisionar stack completa de observabilidade | false |
with_portainer |
Provisionar Portainer | false |
with_portainer_agent |
Provisionar apenas Portainer Agent | false |
Exemplo de Uso:
# ansible/inventory/production.yml
app_servers:
hosts:
prod-pagesaude-app-01:
with_traefik: true
with_apps: true
Flags de Monitoramento¶
Controlam a coleta de métricas e logs de serviços específicos:
| Variável | Descrição |
|---|---|
monitor_postgres |
Habilitar coleta de métricas PostgreSQL |
monitor_redis |
Habilitar coleta de métricas Redis |
monitor_apache |
Habilitar coleta de métricas e logs Apache |
Nota: As flags
with_*automaticamente habilitam o monitoramento correspondente. Use as flagsmonitor_*para monitorar serviços existentes que não são provisionados pelo Ansible.
Variáveis Globais¶
Definidas na seção vars: do inventário:
| Variável | Descrição | Exemplo |
|---|---|---|
deploy_environment |
Ambiente de deploy (abreviado) | prod, stg, local |
grafana_domain |
Domínio do Grafana | grafana-ops.pagesaude.com.br |
otlp_exporter_endpoint |
Endpoint do coletor OTLP | 192.168.100.21:4317 |
pyroscope_writer_endpoint |
Endpoint do Pyroscope | http://192.168.100.21:4380 |
Deploy de Aplicações¶
Aplicações são gerenciadas em seus próprios repositórios e publicadas no diretório apps/ dos servidores de produção.
[!IMPORTANT] Em produção, devem ser publicados apenas os arquivos de docker-compose apontando para imagens de produção já construídas no GitHub Container Registry. O código fonte não deve ser copiado para os servidores de produção.
Estrutura Recomendada no Repositório do Projeto¶
Cada projeto deve manter sua configuração Docker organizada:
<projeto>/
├── docker-compose.yaml # Desenvolvimento local (monta código, hot-reload, etc.)
├── .env.example # Template de variáveis de ambiente
└── .docker/
├── Dockerfile # Build da imagem de produção
└── compose.yaml # Compose de produção (publicado em apps/)
Estrutura de Produção (Servidor)¶
O diretório apps/ no servidor contém apenas os arquivos necessários para execução:
apps/<nome-app>/
├── compose.yaml # Cópia de .docker/compose.yaml do projeto
└── .env # Variáveis de ambiente (gerado pelo GitHub Actions)
Exemplo de Compose de Produção¶
services:
meu-servico:
image: ghcr.io/pagesaude/meu-projeto:1.2.3 # GitHub Container Registry
# ... demais configurações
Integração com Traefik¶
Para expor a aplicação via Traefik, adicione labels ao serviço no compose.yaml:
services:
meu-servico:
labels:
traefik.enable: 'true'
traefik.http.routers.meu-servico.rule: 'Host(`app.pagesaude.com.br`)'
traefik.http.routers.meu-servico.entrypoints: websecure
traefik.http.routers.meu-servico.tls: 'true'
traefik.http.services.meu-servico.loadbalancer.server.port: '3000'
Regras de Roteamento Comuns:
| Regra | Descrição |
|---|---|
Host(\dominio`)` |
Match por domínio |
PathPrefix(\/api`)` |
Match por prefixo de path |
Host(...) && PathPrefix(...) |
Combinação de regras |
Integração com Monitoramento¶
Coleta de Logs¶
Adicione a label para habilitar coleta automática de logs pelo Alloy Agent:
labels:
monitoring.logs.enabled: 'true'
OpenTelemetry SDK (Traces e Métricas)¶
Configure as variáveis de ambiente para enviar telemetria ao Alloy Agent:
environment:
OTEL_SERVICE_NAME: meu-servico
OTEL_EXPORTER_OTLP_ENDPOINT: http://alloy-agent:4318
OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
OTEL_PROPAGATORS: baggage,tracecontext
OTEL_RESOURCE_ATTRIBUTES: >
deployment.environment=prod,
service.namespace=pagesaude,
service.name=meu-servico,
service.type=backend
Atributos Obrigatórios (ver ADR-0002):
| Atributo | Descrição | Exemplo |
|---|---|---|
deployment.environment |
Ambiente | prod, stg, local |
service.namespace |
Produto/domínio | pagesaude, credencia |
service.name |
Nome do serviço | auth-service |
service.type |
Tipo do serviço | backend, frontend |
Labels de Container (Observabilidade)¶
Para melhor correlação no Grafana, adicione também labels ao container:
labels:
deployment.environment: prod
service.namespace: pagesaude
service.name: meu-servico
service.type: backend
Rede Docker¶
Use a rede externa pagesaude para comunicação entre serviços:
networks:
pagesaude:
external: true
Exemplo Completo¶
A aplicação de exemplo saiu deste repositório. O histórico dela está preservado na branch example-node-export (gerada com git subtree split --prefix=apps/example-node), pronta para virar um repositório próprio. O guia de integração de telemetria está em monitoring.md.