Resposta a incidentes no Azure: automação de alertas, runbooks e integração com ferramentas de on-call

Resposta a incidentes no Azure: automação de alertas, runbooks e integração com ferramentas de on-call

8 de Abril de 2026

Você já validou a resiliência com Engenharia de Caos, definiu SLIs, SLOs e Error Budgets. Mas quando o incidente real acontece , e vai acontecer, a pergunta que define o impacto não é "o que deu errado?", mas sim: "quanto tempo levamos para detectar, responder e resolver?"

Esse tempo tem nome: MTTD (Mean Time to Detect), MTTE (Mean Time to Engage) e MTTR (Mean Time to Recover). E a diferença entre um incidente de 5 minutos e um de 5 horas está diretamente ligada à qualidade do seu processo de resposta a incidentes e, principalmente, ao nível de automação que você tem.

Neste artigo, vamos explorar como construir um fluxo completo de resposta a incidentes no Azure: desde alertas inteligentes com Azure Monitor, passando por automação com Action Groups e Runbooks, até a integração com ferramentas de on-call e a prática de post-mortems blameless.

Por que resposta a incidentes importa mais do que prevenção?

Parece contraintuitivo, mas é uma premissa fundamental de SRE: você não pode prevenir todos os incidentes. Sistemas distribuídos falham de formas imprevisíveis, é a natureza da complexidade.

O que separa organizações maduras das demais não é a ausência de incidentes, mas a velocidade e qualidade da resposta:

MétricaO que medeMeta típica
MTTD (Mean Time to Detect)Quanto tempo até o sistema detectar a anomalia< 5 minutos
MTTE (Mean Time to Engage)Quanto tempo até uma pessoa qualificada ser notificada e começar a investigar< 15 minutos
MTTR (Mean Time to Recover)Quanto tempo até o serviço voltar ao estado estável< 60 minutos
MTTF (Mean Time to Fix)Quanto tempo até a causa raiz ser corrigida permanentementeVaria por severidade
O objetivo não é eliminar incidentes, é reduzir MTTD, MTTE e MTTR continuamente. Se você consegue detectar em 2 minutos, engajar em 5 e recuperar em 15, o impacto para o usuário é mínimo, mesmo que a falha seja séria.

Anatomia de um fluxo de resposta a incidentes no Azure

Um fluxo maduro de incident response no Azure envolve quatro camadas:

┌────────────────────────────────────────────────────────────────┐
│  1. DETECÇÃO           Azure Monitor Alerts, Log Analytics,    │
│                        Application Insights, Service Health    │
├────────────────────────────────────────────────────────────────┤
│  2. NOTIFICAÇÃO        Action Groups (email, SMS, webhook,     │
│                        Azure Functions, Logic Apps)            │
├────────────────────────────────────────────────────────────────┤
│  3. AUTOMAÇÃO          Automation Runbooks, Azure Functions,   │
│                        Logic Apps, auto-remediation            │
├────────────────────────────────────────────────────────────────┤
│  4. GESTÃO             Integração com on-call tools,           │
│                        war rooms, post-mortems                 │
└────────────────────────────────────────────────────────────────┘

Vamos detalhar cada uma.

Camada 1: Detecção | Alertas inteligentes com Azure Monitor

A primeira linha de defesa é a detecção automática. Alertas mal configurados são piores do que nenhum alerta, geram fadiga (alert fatigue) e fazem a equipe ignorar notificações reais.

Tipos de alerta no Azure Monitor

TipoUso idealLatência típica
Metric alertsMétricas numéricas (CPU, memória, latência, taxa de erro)~1 minuto
Log search alertsQueries KQL em Log Analytics ou Application Insights1-15 minutos (configurável)
Activity log alertsEventos do plano de controle (VM deletada, role assignment, deployment)~1-5 minutos
Service Health alertsIncidentes do próprio Azure (outages, manutenções planejadas)Tempo real
Smart DetectionAnomalias detectadas automaticamente pelo Application InsightsAutomático

Alertas baseados em SLOs

Se você já definiu SLOs (como no artigo anterior), seus alertas devem refletir isso. A ideia é alertar quando o error budget está sendo consumido rápido demais, não apenas quando uma métrica pontual ultrapassa um limiar.

// SLI: taxa de sucesso das requisições (últimas 6 horas, janela deslizante)
let sloTarget = 99.9;
let windowSize = 6h;
requests
| where timestamp >= ago(windowSize)
| summarize
    totalRequests = count(),
    successfulRequests = countif(success == true)
| extend
    successRate = round(100.0 * successfulRequests / totalRequests, 3),
    sloTarget = sloTarget,
    errorBudgetTotal = round(100.0 - sloTarget, 3),
    errorBudgetConsumed = round(100.0 - (100.0 * successfulRequests / totalRequests), 3)
| extend
    errorBudgetRemainingPct = round(100.0 * (1 - errorBudgetConsumed / errorBudgetTotal), 2)
| where errorBudgetRemainingPct < 50

Burn rate alerts, o padrão recomendado pelo Google SRE

Em vez de alertar quando o SLO é violado (reativo demais) ou quando qualquer erro acontece (barulhento demais), use burn rate alerts:

// Burn rate: quantas vezes mais rápido que o normal o error budget está sendo consumido
// Burn rate = 1 significa consumo normal (o budget duraria exatamente a janela do SLO)
// Burn rate > 14 em 1h = alerta crítico (budget se esgota em ~2 dias)
// Burn rate > 6 em 6h = alerta de warning (budget se esgota em ~5 dias)
let sloTarget = 0.999;
let sloPeriod = 30d;
let shortWindow = 1h;
let longWindow = 6h;
let burnRateThresholdCritical = 14.0;
let burnRateThresholdWarning = 6.0;
let errorBudget = 1 - sloTarget;
// Janela curta (1h)
let shortWindowErrors = requests
| where timestamp >= ago(shortWindow)
| summarize
    total = count(),
    errors = countif(success == false)
| extend errorRate = 1.0 * errors / total
| extend burnRate = errorRate / errorBudget;
// Janela longa (6h)
let longWindowErrors = requests
| where timestamp >= ago(longWindow)
| summarize
    total = count(),
    errors = countif(success == false)
| extend errorRate = 1.0 * errors / total
| extend burnRate = errorRate / errorBudget;
shortWindowErrors
| extend windowType = "short", threshold = burnRateThresholdCritical
| union (longWindowErrors | extend windowType = "long", threshold = burnRateThresholdWarning)
| where burnRate > threshold

Criando o alerta via CLI

# Criar um log search alert baseado em burn rate
az monitor scheduled-query create \
  --name "alert-slo-burn-rate-critical" \
  --resource-group meu-rg \
  --scopes "/subscriptions/<sub-id>/resourceGroups/meu-rg/providers/Microsoft.Insights/components/meu-appinsights" \
  --condition "count 'requests | where timestamp >= ago(1h) | summarize total=count(), errors=countif(success==false) | extend burnRate=(1.0*errors/total)/0.001 | where burnRate > 14' > 0" \
  --severity 0 \
  --evaluation-frequency 5m \
  --window-size 10m \
  --action-groups "/subscriptions/<sub-id>/resourceGroups/meu-rg/providers/Microsoft.Insights/actionGroups/ag-critical-oncall"

Boas práticas para evitar alert fatigue

PráticaPor que
Categorize por severidadeSev0 (crítico) aciona on-call imediatamente. Sev3 (informativo) vai para um canal de Slack/Teams.
Use supressão temporalNão alerte 50 vezes pelo mesmo problema. Configure autoMitigate e períodos de supressão.
Alerte sobre sintomas, não causasAlerte "taxa de erro acima de 1%" e não "CPU acima de 80%". CPU alta pode ser normal sob carga.
Revise alertas regularmenteAlertas que nunca disparam ou sempre disparam são igualmente inúteis. Faça alert hygiene mensal.
Defina dono para cada alertaTodo alerta precisa ter um time responsável. Alerta sem dono = alerta ignorado.

Camada 2: Notificação | Action Groups

Os Action Groups do Azure Monitor são o hub central de notificação. Eles definem quem e como será notificado quando um alerta dispara.

Tipos de ação disponíveis

TipoUso
Email/SMS/VozNotificação direta a pessoas
Azure FunctionExecução de código serverless para automação ou enriquecimento
Logic AppOrquestração de workflows complexos
WebhookIntegração com ferramentas externas (PagerDuty, OpsGenie, Slack, Teams)
Automation RunbookExecução de scripts de remediação automática
ITSMIntegração com ServiceNow, Provance, etc.
Event HubStreaming de alertas para pipelines de dados
Secure WebhookWebhook com autenticação via Azure AD

Criando um Action Group com múltiplas ações

# Criar action group que combina notificação + automação
az monitor action-group create \
  --name ag-critical-oncall \
  --resource-group meu-rg \
  --short-name CritOnCall \
  --action email oncall-team oncall@empresa.com \
  --action sms oncall-sms "+5511999999999" \
  --action webhook pagerduty-integration "https://events.pagerduty.com/integration/<key>/enqueue" \
  --action automation-runbook auto-restart-service \
    "/subscriptions/<sub-id>/resourceGroups/meu-rg/providers/Microsoft.Automation/automationAccounts/meu-automation/runbooks/Restart-UnhealthyService" \
    "/subscriptions/<sub-id>/resourceGroups/meu-rg/providers/Microsoft.Automation/automationAccounts/meu-automation" \
    true

Estratégia de escalonamento por severidade

Uma boa prática é criar Action Groups diferentes por nível de severidade:

Sev0 (Crítico)     → ag-sev0: PagerDuty (on-call) + SMS + Runbook auto-remediação
Sev1 (Alto)        → ag-sev1: Teams channel + Email do time + Ticket ITSM
Sev2 (Médio)       → ag-sev2: Teams channel + Email
Sev3 (Informativo) → ag-sev3: Log centralizado + Dashboard
# Exemplo: Action Group para Sev1 com criação automática de ticket
az monitor action-group create \
  --name ag-sev1-high \
  --resource-group meu-rg \
  --short-name Sev1High \
  --action email platform-team platform@empresa.com \
  --action webhook teams-channel "https://outlook.office.com/webhook/<teams-webhook-url>" \
  --action logic-app create-ticket \
    "/subscriptions/<sub-id>/resourceGroups/meu-rg/providers/Microsoft.Logic/workflows/lapp-create-incident-ticket" \
    "https://<logic-app-trigger-url>"

Camada 3: Automação | Runbooks e auto-remediação

Aqui é onde a mágica acontece. Em vez de apenas notificar uma pessoa para executar um procedimento manual, automatize as ações de remediação mais comuns.

Azure Automation Runbooks

Runbooks são scripts (PowerShell ou Python) que rodam no Azure Automation e podem ser acionados automaticamente por alertas.

Exemplo 1: Reiniciar um App Service não saudável

# Runbook: Restart-UnhealthyAppService.ps1
param(
    [Parameter(Mandatory=$true)]
    [object]$WebhookData
)

# Parsear o payload do alerta
$alertPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody
$alertContext = $alertPayload.data.alertContext
$resourceId = $alertPayload.data.essentials.alertTargetIDs[0]

# Extrair informações do recurso
$resourceParts = $resourceId -split '/'
$resourceGroupName = $resourceParts[4]
$appServiceName = $resourceParts[8]

Write-Output "Alerta recebido: $($alertPayload.data.essentials.alertRule)"
Write-Output "Recurso afetado: $appServiceName no RG $resourceGroupName"

# Conectar usando Managed Identity
Connect-AzAccount -Identity

# Verificar o estado atual
$app = Get-AzWebApp -ResourceGroupName $resourceGroupName -Name $appServiceName
Write-Output "Estado atual: $($app.State)"

if ($app.State -ne "Running" -or $alertContext) {
    Write-Output "Reiniciando App Service $appServiceName..."
    Restart-AzWebApp -ResourceGroupName $resourceGroupName -Name $appServiceName

    # Aguardar e verificar
    Start-Sleep -Seconds 30
    $app = Get-AzWebApp -ResourceGroupName $resourceGroupName -Name $appServiceName
    Write-Output "Estado após restart: $($app.State)"

    if ($app.State -eq "Running") {
        Write-Output "✅ App Service reiniciado com sucesso."
    } else {
        Write-Output "⚠️ App Service não voltou ao estado Running. Escalonando para equipe."
        # Aqui você poderia chamar outro webhook para escalonar
    }
}

Exemplo 2: Escalar um VMSS quando CPU está crítica

# Runbook: Scale-OutVMSS.ps1
param(
    [Parameter(Mandatory=$true)]
    [object]$WebhookData
)

$alertPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody
$resourceId = $alertPayload.data.essentials.alertTargetIDs[0]

$resourceParts = $resourceId -split '/'
$resourceGroupName = $resourceParts[4]
$vmssName = $resourceParts[8]

Connect-AzAccount -Identity

$vmss = Get-AzVmss -ResourceGroupName $resourceGroupName -VMScaleSetName $vmssName
$currentCapacity = $vmss.Sku.Capacity
$maxCapacity = 20
$scaleIncrement = 2

Write-Output "VMSS: $vmssName | Capacidade atual: $currentCapacity"

if ($currentCapacity + $scaleIncrement -le $maxCapacity) {
    $newCapacity = $currentCapacity + $scaleIncrement
    Write-Output "Escalando de $currentCapacity para $newCapacity instâncias..."

    $vmss.Sku.Capacity = $newCapacity
    Update-AzVmss -ResourceGroupName $resourceGroupName `
                  -VMScaleSetName $vmssName `
                  -VirtualMachineScaleSet $vmss

    Write-Output "✅ VMSS escalado para $newCapacity instâncias."
} else {
    Write-Output "⚠️ Capacidade máxima ($maxCapacity) atingida. Escalonando para equipe."
}

Exemplo 3: Diagnosticar e coletar evidências automaticamente

Nem toda automação precisa remediar. Às vezes, o mais valioso é coletar informações diagnósticas automaticamente para acelerar a investigação humana:

# Runbook: Collect-IncidentDiagnostics.ps1
param(
    [Parameter(Mandatory=$true)]
    [object]$WebhookData
)

$alertPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody
$resourceId = $alertPayload.data.essentials.alertTargetIDs[0]
$alertTime = $alertPayload.data.essentials.firedDateTime

Connect-AzAccount -Identity

# Coletar métricas dos últimos 30 minutos
$startTime = (Get-Date $alertTime).AddMinutes(-30)
$endTime = Get-Date $alertTime

Write-Output "=== Diagnóstico automático de incidente ==="
Write-Output "Recurso: $resourceId"
Write-Output "Hora do alerta: $alertTime"
Write-Output "Janela de análise: $startTime até $endTime"

# Coletar métricas
$metrics = Get-AzMetric -ResourceId $resourceId `
    -TimeGrain 00:01:00 `
    -StartTime $startTime `
    -EndTime $endTime `
    -MetricName "CpuPercentage","MemoryPercentage","Http5xx","HttpResponseTime"

foreach ($metric in $metrics) {
    Write-Output "`n--- $($metric.Name.Value) ---"
    $metric.Data | Where-Object { $_.Average -ne $null } |
        Select-Object TimeStamp, Average, Maximum |
        Format-Table -AutoSize
}

# Coletar logs recentes do Activity Log
$activityLogs = Get-AzActivityLog `
    -StartTime $startTime `
    -EndTime $endTime `
    -ResourceId $resourceId `
    -MaxRecord 20

Write-Output "`n=== Activity Log (últimos 30 min) ==="
$activityLogs | Select-Object EventTimestamp, OperationName, Status, Caller |
    Format-Table -AutoSize

# Salvar resultado em um blob para referência
$diagnosticReport = @{
    AlertRule = $alertPayload.data.essentials.alertRule
    Severity = $alertPayload.data.essentials.severity
    FiredAt = $alertTime
    Resource = $resourceId
    MetricsSummary = $metrics | ForEach-Object {
        @{ Name = $_.Name.Value; MaxValue = ($_.Data | Measure-Object -Property Maximum -Maximum).Maximum }
    }
    RecentActivity = $activityLogs | Select-Object EventTimestamp, OperationName, Status
}

$reportJson = $diagnosticReport | ConvertTo-Json -Depth 5
Write-Output "`n=== Relatório JSON ==="
Write-Output $reportJson

Decisão: quando automatizar vs. quando escalonar

Nem tudo deve ser automatizado. Use esta heurística:

CenárioAção recomendada
Problema conhecido com solução determinística (restart, scale-out)✅ Automatizar completamente
Problema que requer investigação mas tem passos diagnósticos conhecidos⚡ Automatizar coleta de dados, escalonar para humano
Problema raro ou com alto risco de efeito colateral🧑 Notificar humano diretamente
Falha em cascata afetando múltiplos serviços🚨 Escalonar para war room imediatamente

Camada 4: Gestão | Integração com ferramentas de on-call

Alertas do Azure Monitor precisam chegar à pessoa certa, no momento certo. Isso requer integração com ferramentas de on-call rotation e incident management.

Integração com PagerDuty

# Criar webhook no Action Group para PagerDuty
az monitor action-group create \
  --name ag-pagerduty-oncall \
  --resource-group meu-rg \
  --short-name PD-OnCall \
  --action webhook pagerduty \
    "https://events.pagerduty.com/integration/<integration-key>/enqueue"

A integração nativa do PagerDuty com Azure Monitor já faz o mapeamento de severidade:

Azure Monitor SeverityPagerDuty Urgency
Sev0 (Critical)High
Sev1 (Error)High
Sev2 (Warning)Low
Sev3 (Informational)Low

Integração com Microsoft Teams para war rooms

Use Logic Apps para criar canais dedicados de war room automaticamente quando um incidente Sev0 é declarado:

{
  "definition": {
    "triggers": {
      "When_alert_fires": {
        "type": "Request",
        "kind": "Http",
        "inputs": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "object",
                "properties": {
                  "essentials": {
                    "type": "object",
                    "properties": {
                      "alertRule": { "type": "string" },
                      "severity": { "type": "string" },
                      "firedDateTime": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "actions": {
      "Create_Teams_Channel": {
        "type": "ApiConnection",
        "inputs": {
          "method": "post",
          "path": "/v1.0/teams/<team-id>/channels",
          "body": {
            "displayName": "🚨 INC-@{formatDateTime(utcNow(), 'yyyyMMdd-HHmm')}",
            "description": "War room para incidente: @{triggerBody()?['data']?['essentials']?['alertRule']}"
          }
        }
      },
      "Post_Initial_Message": {
        "type": "ApiConnection",
        "runAfter": { "Create_Teams_Channel": ["Succeeded"] },
        "inputs": {
          "method": "post",
          "path": "/v1.0/teams/<team-id>/channels/@{body('Create_Teams_Channel')?['id']}/messages",
          "body": {
            "body": {
              "contentType": "html",
              "content": "<h2>🚨 Incidente Declarado</h2><p><b>Alerta:</b> @{triggerBody()?['data']?['essentials']?['alertRule']}</p><p><b>Severidade:</b> @{triggerBody()?['data']?['essentials']?['severity']}</p><p><b>Hora:</b> @{triggerBody()?['data']?['essentials']?['firedDateTime']}</p><hr/><p><b>Próximos passos:</b></p><ul><li>Incident Commander: [a ser definido]</li><li>Comunicação: atualizações a cada 15 min</li><li>Runbook: consultar Wiki/Runbooks</li></ul>"
            }
          }
        }
      }
    }
  }
}

Integração com Azure DevOps para tracking

Automatize a criação de Work Items para cada incidente:

# Usando Azure DevOps CLI para criar um bug/incident automaticamente
az boards work-item create \
  --title "INC-$(date +%Y%m%d) - Alerta: <alert-name>" \
  --type "Bug" \
  --org "https://dev.azure.com/minha-org" \
  --project "MeuProjeto" \
  --area "Operations\\Incidents" \
  --fields "System.Tags=incident;sev0" \
           "Microsoft.VSTS.Common.Severity=1 - Critical" \
           "System.Description=<detalhes do alerta>"

Construindo runbooks operacionais eficazes

Além da automação, sua equipe precisa de runbooks documentados para cenários que exigem intervenção humana. Um bom runbook é a diferença entre um engenheiro de on-call resolvendo em 10 minutos e outro levando 2 horas.

Estrutura recomendada para runbooks

# Runbook: [Nome do Cenário]

## Resumo
- **Serviço afetado**: [nome do serviço]
- **Impacto típico**: [o que o usuário percebe]
- **Severidade**: Sev[0-3]
- **SLO relacionado**: [qual SLO é impactado]

## Detecção
- **Alerta**: [nome do alerta no Azure Monitor]
- **Query KQL para validar**:
  ```kusto
  [query para confirmar o problema]

Diagnóstico

  1. Verificar [métrica/log/dashboard]
  2. Confirmar se [condição] é verdadeira
  3. Checar dependências: [lista de dependências]

Remediação

Caminho 1: [cenário mais comum]

  1. Executar: [comando]
  2. Verificar: [validação]
  3. Confirmar recuperação no dashboard

Caminho 2: [cenário alternativo]

  1. Se o Caminho 1 não funcionar, [próxima ação]

Escalonamento

  • Se não resolver em [X minutos], escalonar para [time/pessoa]
  • Canal de comunicação: [Teams channel / bridge call]

Post-incidente

  • [ ] Registrar timeline no ticket
  • [ ] Atualizar este runbook se necessário
  • [ ] Agendar post-mortem se Sev0/Sev1

### Vinculando runbooks a alertas

Uma prática poderosa é incluir o link do runbook diretamente na descrição do alerta:

```bash
az monitor metrics alert create \
  --name "alert-api-error-rate-high" \
  --resource-group meu-rg \
  --scopes "<app-insights-resource-id>" \
  --condition "avg requests/failed > 10" \
  --severity 1 \
  --action ag-sev1-high \
  --description "Taxa de erro da API acima do limiar. Runbook: https://wiki.empresa.com/runbooks/api-error-rate-high"

Post-mortems blameless: aprendendo com incidentes

O ciclo de resposta a incidentes não termina quando o serviço volta ao normal. A etapa mais importante para melhoria contínua é o post-mortem blameless, uma análise estruturada do incidente focada em aprendizado, não em culpa.

Por que "blameless"?

Se as pessoas têm medo de serem punidas, elas escondem informações. Se escondem informações, você nunca descobre a causa raiz real. A cultura blameless entende que:

Sistemas complexos falham por múltiplos fatores combinados. Culpar uma pessoa é simplificar demais e perder a chance de corrigir o sistema.

Template de post-mortem

# Post-Mortem: INC-20260324

## Resumo executivo
- **Data do incidente**: 2026-03-24
- **Duração**: 47 minutos (14:03 - 14:50 UTC)
- **Severidade**: Sev1
- **Impacto**: 12% das requisições da API retornaram erro 503
- **Usuários afetados**: ~3.200
- **SLO impactado**: Disponibilidade (target: 99.9%, real na janela: 99.2%)
- **Error budget consumido**: 8.4% do budget mensal

## Timeline
| Hora (UTC) | Evento |
|------------|--------|
| 14:00 | Deploy v2.14.3 iniciado no slot de staging |
| 14:03 | Swap de slots executado (staging → production) |
| 14:05 | Alerta "API Error Rate > 1%" disparou (MTTD: 2 min) |
| 14:08 | On-call recebe notificação PagerDuty (MTTE: 5 min) |
| 14:12 | On-call confirma erro 503 no Application Insights |
| 14:15 | Identificada connection string incorreta no novo deployment |
| 14:18 | Rollback iniciado (swap reverso) |
| 14:22 | Rollback concluído, erros cessam |
| 14:50 | Métricas confirmam retorno ao estado estável (MTTR: 47 min) |

## Causa raiz
A variável de ambiente `COSMOS_CONNECTION_STRING` foi alterada no
App Configuration mas não foi atualizada no slot de staging. O swap
de slots carregou a configuração desatualizada em produção.

## Fatores contribuintes
1. Não havia validação automatizada de configurações pré-swap.
2. O health check do slot não testava conectividade com Cosmos DB.
3. O runbook de deploy não incluía verificação de App Configuration.

## O que funcionou bem
- ✅ Alerta disparou em 2 minutos (dentro do target de MTTD).
- ✅ On-call respondeu em 5 minutos (dentro do target de MTTE).
- ✅ Rollback foi rápido graças ao uso de deployment slots.

## O que pode melhorar
- ⚠️ Health check precisa validar dependências (DB, cache, etc.).
- ⚠️ Pipeline de deploy precisa validar configurações antes do swap.
- ⚠️ Faltava alerta de "configuração divergente entre slots".

## Ações corretivas (Action Items)
| # | Ação | Responsável | Prazo | Status |
|---|------|-------------|-------|--------|
| 1 | Adicionar health check que valida Cosmos DB | Time Backend | 1 semana | Pendente |
| 2 | Criar step no pipeline que compara App Config entre slots | Time DevOps | 2 semanas | Pendente |
| 3 | Adicionar alerta de drift de configuração | Time SRE | 1 semana | Pendente |
| 4 | Atualizar runbook de deploy com checklist pré-swap | Time DevOps | 1 semana | Pendente |

KQL para análise de post-mortem

Durante o post-mortem, queries KQL ajudam a reconstruir a timeline com precisão:

// Reconstruir o impacto do incidente minuto a minuto
let incidentStart = datetime(2026-03-24T14:00:00Z);
let incidentEnd = datetime(2026-03-24T15:00:00Z);
requests
| where timestamp between (incidentStart .. incidentEnd)
| summarize
    totalRequests = count(),
    failedRequests = countif(resultCode startswith "5"),
    avgDuration = avg(duration),
    p95Duration = percentile(duration, 95),
    p99Duration = percentile(duration, 99)
  by bin(timestamp, 1m)
| extend errorRate = round(100.0 * failedRequests / totalRequests, 2)
| order by timestamp asc
// Identificar quais operações foram mais afetadas
let incidentStart = datetime(2026-03-24T14:03:00Z);
let incidentEnd = datetime(2026-03-24T14:22:00Z);
requests
| where timestamp between (incidentStart .. incidentEnd)
| where success == false
| summarize
    failedCount = count(),
    distinctUsers = dcount(user_Id)
  by name, resultCode
| order by failedCount desc
| take 10
// Correlacionar com mudanças no Activity Log (deploys, config changes)
AzureActivity
| where TimeGenerated between (datetime(2026-03-24T13:30:00Z) .. datetime(2026-03-24T15:00:00Z))
| where OperationNameValue has_any ("Microsoft.Web/sites/slots/slotsswap",
                                      "Microsoft.Web/sites/config/write",
                                      "Microsoft.AppConfiguration")
| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller
| order by TimeGenerated asc

Montando a operação: um framework completo

Juntando tudo, aqui está como organizar sua operação de resposta a incidentes no Azure:

1. Antes do incidente (preparação)

  • SLIs e SLOs definidos (com burn rate alerts configurados).
  • Action Groups criados por severidade, com escalation path claro.
  • Runbooks documentados e vinculados a cada alerta.
  • Automação configurada para cenários conhecidos (restart, scale-out, diagnóstico).
  • Rotação de on-call definida na ferramenta de incident management.
  • Game Day periódico para testar o fluxo completo (veja nosso artigo sobre Engenharia de Caos).

2. Durante o incidente (resposta)

Alerta dispara
    ↓
Action Group notifica on-call + executa automação
    ↓
On-call avalia: automação resolveu?
    ├── SIM → Verificar métricas, fechar alerta, registrar
    └── NÃO → Seguir runbook
                 ↓
              Resolveu?
              ├── SIM → Registrar e monitorar
              └── NÃO → Escalonar
                          ↓
                       War room (Teams channel automático)
                          ↓
                       Incident Commander coordena resposta
                          ↓
                       Resolução + comunicação para stakeholders

3. Depois do incidente (aprendizado)

  • Post-mortem blameless em até 48 horas (para Sev0/Sev1).
  • Action items registrados e rastreados até conclusão.
  • Runbooks atualizados com os aprendizados.
  • Alertas revisados, precisa de novo alerta? Algum alerta precisa ser ajustado?
  • Novo experimento de caos para validar as correções.

Métricas operacionais: medindo a maturidade

Para saber se sua operação está melhorando, acompanhe estas métricas ao longo do tempo:

MétricaComo medirMeta
MTTDTimestamp do alerta - timestamp do início real do problemaDiminuir mês a mês
MTTETimestamp do acknowledge - timestamp do alerta< 15 min para Sev0
MTTRTimestamp da recuperação - timestamp do inícioDiminuir mês a mês
Incidentes/mêsContagem de incidentes Sev0+Sev1Diminuir mês a mês
% de auto-remediaçãoIncidentes resolvidos por automação / totalAumentar mês a mês
Action items concluídosItems de post-mortem fechados / abertos> 80% no prazo
Alert fatigueAlertas que não resultaram em ação / total de alertas< 20%
// Dashboard KQL: MTTR por mês (requer custom tracking table)
IncidentTracking_CL
| where TimeGenerated >= ago(180d)
| where Severity_s in ("Sev0", "Sev1")
| extend MTTR_minutes = datetime_diff('minute', ResolvedAt_t, DetectedAt_t)
| summarize
    avgMTTR = avg(MTTR_minutes),
    p50MTTR = percentile(MTTR_minutes, 50),
    p95MTTR = percentile(MTTR_minutes, 95),
    incidentCount = count()
  by bin(TimeGenerated, 30d)
| order by TimeGenerated asc

Conclusão

Resposta a incidentes não é sobre ter um herói que acorda às 3h da manhã e resolve tudo sozinho. É sobre construir um sistema de alertas inteligentes, automação confiável, processos claros e cultura de aprendizado que minimiza o impacto dos incidentes inevitáveis.

No Azure, você tem todas as peças: Azure Monitor para detecção, Action Groups para notificação, Automation Runbooks e Logic Apps para automação, e integração nativa com ferramentas de on-call como PagerDuty e Microsoft Teams.

A jornada que construímos nos últimos artigos forma um ciclo completo:

  1. Engenharia de Caos → Descubra fragilidades antes que elas virem incidentes.
  2. SRE (SLIs/SLOs/Error Budgets) → Meça a confiabilidade com dados objetivos.
  3. Resposta a Incidentes → Quando o incidente acontecer, detecte rápido, responda com automação e aprenda com cada ocorrência.

O resultado é um sistema que não apenas é resiliente por design, mas que melhora continuamente a cada incidente. E essa é a verdadeira essência de operações maduras na nuvem.

Confira mais:

Fique por dentro das novidades

Assine nossa newsletter e receba as últimas atualizações e artigos diretamente em seu email.

Assinar gratuitamente