Pular para conteúdo

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_passwordpostgres_password Senha do usuário PostgreSQL provisionado.
REDIS_PASSWORD input_redis_passwordredis_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, ./provisionPOSTGRES_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_connections via 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 flags monitor_* 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.

Referências