☁️

Azure Infrastructure Setup

🚀 Setup de Infraestrutura Azure - Audissey

Este guia contém os comandos necessários para configurar a infraestrutura Azure que ainda não está automatizada no pipeline.

📋 Pré-requisitos


1️⃣ **CRÍTICO**: Cosmos DB (MongoDB API)

Nota: no Cosmos DB (Mongo API), algumas queries com ORDER BY/.sort() podem falhar com 400 BadRequest (ex: The index path corresponding to the specified order-by item is excluded.) quando o campo usado para ordenação não está indexado (ou foi excluído por policy).

Nesses casos, o backend pode precisar de:

  • garantir index para o campo ordenado (ex: createdAt) ou
  • implementar fallback (buscar sem sort e ordenar em memória) para manter o endpoint funcional.

No caso específico de favorites, a API tenta ordenar por createdAt e tem fallback seguro para ordenação por _id se o Cosmos rejeitar o ORDER BY. Também tenta criar indexes relevantes no arranque (best-effort).

# Criar Cosmos DB com MongoDB API
az cosmosdb create \
  --name audissey-cosmos \
  --resource-group audissey-rg \
  --kind MongoDB \
  --server-version 7.0 \
  --locations regionName=westeurope failoverPriority=0 isZoneRedundant=false \
  --default-consistency-level Session \
  --enable-automatic-failover true \
  --enable-free-tier false

# Criar database
az cosmosdb mongodb database create \
  --account-name audissey-cosmos \
  --resource-group audissey-rg \
  --name audissey

# Obter connection string
az cosmosdb keys list \
  --name audissey-cosmos \
  --resource-group audissey-rg \
  --type connection-strings \
  --query "connectionStrings[0].connectionString" -o tsv

# Guardar no Key Vault
MONGO_URI=$(az cosmosdb keys list --name audissey-cosmos --resource-group audissey-rg --type connection-strings --query "connectionStrings[0].connectionString" -o tsv)

az keyvault secret set \
  --vault-name audissey-kv-production \
  --name MONGO-URI \
  --value "$MONGO_URI"

Custo estimado: ~€30-50/mês (depende do throughput)


2️⃣ **CRÍTICO**: Azure Cache for Redis

# Criar Redis Cache (Standard C1 = 1GB)
az redis create \
  --name audissey-redis \
  --resource-group audissey-rg \
  --location westeurope \
  --sku Standard \
  --vm-size C1 \
  --enable-non-ssl-port false

# Obter connection string
REDIS_HOST=$(az redis show --name audissey-redis --resource-group audissey-rg --query hostName -o tsv)
REDIS_KEY=$(az redis list-keys --name audissey-redis --resource-group audissey-rg --query primaryKey -o tsv)

# Guardar no Key Vault
az keyvault secret set \
  --vault-name audissey-kv-production \
  --name REDIS-HOST \
  --value "$REDIS_HOST"

az keyvault secret set \
  --vault-name audissey-kv-production \
  --name REDIS-KEY \
  --value "$REDIS_KEY"

Custo estimado: ~€70/mês (Standard C1)


3️⃣ **IMPORTANTE**: App Services Staging/Dev

# Criar App Service para Staging
az webapp create \
  --name audissey-api-staging \
  --resource-group audissey-rg \
  --plan audissey-plan \
  --runtime "NODE:18-lts"

# Criar App Service para Development
az webapp create \
  --name audissey-api-dev \
  --resource-group audissey-rg \
  --plan audissey-plan \
  --runtime "NODE:18-lts"

# Configurar HTTPS Only
az webapp update \
  --name audissey-api-staging \
  --resource-group audissey-rg \
  --https-only true

az webapp update \
  --name audissey-api-dev \
  --resource-group audissey-rg \
  --https-only true

Custo: Incluído no plano existente (audissey-plan)


4️⃣ **IMPORTANTE**: Container Registry (ACR)

# ACR oficial (shared): audissey.azurecr.io (RG: audissey-shared-rg)
# Nota: o Admin User está desativado.

# Verificar o registry
az acr show \
  --name audissey \
  --resource-group audissey-shared-rg \
  --query "{name:name, loginServer:loginServer, adminUserEnabled:adminUserEnabled}" \
  -o jsonc

# Login (local) via Azure AD
az acr login --name audissey

# Exemplo: build/push
docker build -f Dockerfile.worker -t audissey.azurecr.io/audissey-worker:<tag> .
docker push audissey.azurecr.io/audissey-worker:<tag>

# App Service pull deve ser via Managed Identity + role AcrPull.

Custo estimado: ~€5/mês (Basic tier)


5️⃣ **IMPORTANTE**: Key Vault Secrets

# Adicionar secrets essenciais ao Key Vault de produção
VAULT_NAME="audissey-kv-production"

# JWT Secret
az keyvault secret set \
  --vault-name $VAULT_NAME \
  --name JWT-SECRET \
  --value "$(openssl rand -base64 32)"

# Podcast Index API
az keyvault secret set \
  --vault-name $VAULT_NAME \
  --name PODCAST-INDEX-API-KEY \
  --value "your_api_key_here"

az keyvault secret set \
  --vault-name $VAULT_NAME \
  --name PODCAST-INDEX-API-SECRET \
  --value "your_api_secret_here"

# Repetir para staging e dev vaults
VAULT_NAME="audissey-kv-staging"
# ... (mesmos comandos)

VAULT_NAME="audissey-kv-dev"
# ... (mesmos comandos)

6️⃣ **IMPORTANTE**: Configurar App Service com Key Vault References

# Configurar Managed Identity no App Service
az webapp identity assign \
  --name audissey-api \
  --resource-group audissey-rg

# Obter o Principal ID
PRINCIPAL_ID=$(az webapp identity show \
  --name audissey-api \
  --resource-group audissey-rg \
  --query principalId -o tsv)

# Dar permissões ao Key Vault
az keyvault set-policy \
  --name audissey-kv-production \
  --object-id $PRINCIPAL_ID \
  --secret-permissions get list

# Configurar App Settings com referências ao Key Vault
az webapp config appsettings set \
  --name audissey-api \
  --resource-group audissey-rg \
  --settings \
    MONGO_URI="@Microsoft.KeyVault(SecretUri=https://audissey-kv-production.vault.azure.net/secrets/MONGO-URI/)" \
    REDIS_HOST="@Microsoft.KeyVault(SecretUri=https://audissey-kv-production.vault.azure.net/secrets/REDIS-HOST/)" \
    REDIS_KEY="@Microsoft.KeyVault(SecretUri=https://audissey-kv-production.vault.azure.net/secrets/REDIS-KEY/)" \
    JWT_SECRET="@Microsoft.KeyVault(SecretUri=https://audissey-kv-production.vault.azure.net/secrets/JWT-SECRET/)" \
    PODCAST_INDEX_API_KEY="@Microsoft.KeyVault(SecretUri=https://audissey-kv-production.vault.azure.net/secrets/PODCAST-INDEX-API-KEY/)" \
    PODCAST_INDEX_API_SECRET="@Microsoft.KeyVault(SecretUri=https://audissey-kv-production.vault.azure.net/secrets/PODCAST-INDEX-API-SECRET/)" \
    NODE_ENV="production" \
    API_PORT="8080" \
    LOG_LEVEL="info"

# Repetir para staging e dev

7️⃣ **DESEJÁVEL**: Azure Monitor Alerts

# Criar action group para notificações
az monitor action-group create \
  --name audissey-alerts \
  --resource-group audissey-rg \
  --short-name audissey \
  --email-receiver \
    name=admin \
    email-address=teu-email@example.com

# Alert: CPU > 80%
az monitor metrics alert create \
  --name "API CPU High" \
  --resource-group audissey-rg \
  --scopes $(az webapp show --name audissey-api --resource-group audissey-rg --query id -o tsv) \
  --condition "avg Percentage CPU > 80" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action audissey-alerts

# Alert: Memory > 85%
az monitor metrics alert create \
  --name "API Memory High" \
  --resource-group audissey-rg \
  --scopes $(az webapp show --name audissey-api --resource-group audissey-rg --query id -o tsv) \
  --condition "avg MemoryPercentage > 85" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action audissey-alerts

# Alert: Response Time > 2s
az monitor metrics alert create \
  --name "API Slow Response" \
  --resource-group audissey-rg \
  --scopes $(az webapp show --name audissey-api --resource-group audissey-rg --query id -o tsv) \
  --condition "avg ResponseTime > 2000" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action audissey-alerts

8️⃣ **DESEJÁVEL**: Auto-scaling

# Configurar auto-scale no App Service Plan
az monitor autoscale create \
  --resource-group audissey-rg \
  --resource $(az appservice plan show --name audissey-plan --resource-group audissey-rg --query id -o tsv) \
  --resource-type Microsoft.Web/serverfarms \
  --name audissey-autoscale \
  --min-count 1 \
  --max-count 3 \
  --count 1

# Scale out when CPU > 70%
az monitor autoscale rule create \
  --resource-group audissey-rg \
  --autoscale-name audissey-autoscale \
  --condition "Percentage CPU > 70 avg 5m" \
  --scale out 1

# Scale in when CPU < 30%
az monitor autoscale rule create \
  --resource-group audissey-rg \
  --autoscale-name audissey-autoscale \
  --condition "Percentage CPU < 30 avg 5m" \
  --scale in 1

9️⃣ **DESEJÁVEL**: Backup Automático

# Configurar backup do Cosmos DB
az cosmosdb backup create \
  --account-name audissey-cosmos \
  --resource-group audissey-rg \
  --backup-type Continuous

# Configurar backup do App Service (requer Premium plan)
az webapp config backup create \
  --resource-group audissey-rg \
  --webapp-name audissey-api \
  --container-url "<storage-account-url>" \
  --backup-name daily-backup \
  --frequency 1d \
  --retain-one true

🔟 **Verificação Final**

# Listar todos os recursos criados
az resource list --resource-group audissey-rg --output table

# Verificar custos estimados
az consumption usage list \
  --start-date $(date -u -d '30 days ago' '+%Y-%m-%dT%H:%M:%SZ') \
  --end-date $(date -u '+%Y-%m-%dT%H:%M:%SZ') \
  --query "[?contains(instanceId, 'audissey')].{Name:instanceName, Cost:pretaxCost}" \
  --output table

📊 Resumo de Custos Mensais Estimados

Recurso SKU Custo/mês
App Service Plan B1 €10-15
Cosmos DB 400 RU/s €30-50
Redis Cache Standard C1 €70
Container Registry Basic €5
Application Insights 5GB/mês €0 (free tier)
Container Apps (Worker) Consumption variável (dep. de CPU/mem/execução)
TOTAL €145-180

🚨 Próximos Passos Críticos

  1. ✅ Executar scripts de infraestrutura (pontos 1-6)
  2. ✅ Fazer commit das alterações no pipeline
  3. ✅ Criar service connection para Container Registry no Azure DevOps
  4. ✅ Fazer push da branch staging e develop para testar multi-environment
  5. ✅ Verificar que os secrets estão no Key Vault
  6. ⏳ Testar deployment completo