Quando uma Mudança Simples no GitOps Causa a Perda de Discos no Azure — E Por Que Ter um Parceiro Faz Toda a Diferença

Quando uma Mudança Simples no GitOps Causa a Perda de Discos no Azure — E Por Que Ter um Parceiro Faz Toda a Diferença

Quem trabalha com AKS sabe que o GitOps revolucionou o gerenciamento de infraestrutura. Com ferramentas como ArgoCD, o estado desejado do cluster fica declarado no Git e qualquer desvio é corrigido automaticamente. Mas e quando a automação interpreta uma mudança estrutural como ordem de destruição?

Era pra ser uma reestruturação simples de pastas no repositório Git. Minutos depois, os discos persistentes tinham sido removidos do Azure.

Quem trabalha com Kubernetes em produção sabe que o GitOps trouxe uma revolução na forma como gerenciamos infraestrutura. Ferramentas como o ArgoCD permitem que o estado desejado do cluster seja declarado em um repositório Git, e qualquer desvio é automaticamente corrigido. Mas o que acontece quando essa automação interpreta uma mudança estrutural como uma instrução de destruição?

Esse é o relato de um incidente real que vivenciamos com um cliente, onde uma cadeia de fatores — cada um aparentemente inofensivo isoladamente — culminou na remoção de discos persistentes no Azure. E mais importante: como a resposta rápida, possibilitada por uma parceria sólida, transformou o que poderia ter sido um desastre em um incidente controlado.

O Cenário

O cliente operava um cluster Azure Kubernetes Service (AKS) com ArgoCD como ferramenta de GitOps para gerenciamento de configuração e deploy contínuo. A estrutura do repositório Git era organizada da seguinte forma:

cluster-configuration/
├── namespaces/
├── secrets/
├── storage-classes/
└── ...

Uma pipeline de CD (ContinuousDelivery) era responsável por acionar a sincronização do ArgoCD sempre que havia alterações no repositório. Essa pipeline existia como contorno para um bug conhecido do ArgoCD: quando o repositório é configurado via protocolo git (em vez de https), o WebHook do Azure DevOps não consegue notificar corretamente o ArgoCD sobre atualizações.

O motivo? O WebHook do Azure DevOps envia o caminho completo do repositório incluindo o protocolo HTTPS:

https://dev.azure.com/customer/Customer.Infra.ContinuousDelivery

Enquanto o ArgoCD, por ter clonado o repositório via protocolo git, espera algo como:

git@dev.azure.com/customer/Customer.Infra.ContinuousDelivery

O uso do protocolo git é obrigatório neste caso para permitir a associação de credenciais não pessoais no ArgoCD — uma boa prática de segurança que, ironicamente, criou a necessidade do workaround que contribuiu para o incidente.

O Objetivo da Mudança

O time precisava adaptar o ArgoCD para suportar dois clusters AKS. A mudança consistia em reorganizar a estrutura de pastas, adicionando um nível com o nome do cluster:

cluster-configuration/
├── customer-brasilsouth/
│   ├── namespaces/
│   ├── secrets/
│   └── ...
└── customer-brasilsouth2/
    ├── namespaces/
    ├── secrets/
    └── ...

Além disso, o arquivo argocd/applicationsets/cluster-addons.yaml foi editado para interpretar o primeiro nível da estrutura de diretórios como o nome do cluster alvo de cada manifesto.

Uma mudança estrutural. Sem alteração em nenhum recurso do Kubernetes. O que poderia dar errado?

A Cadeia de Eventos

O que aconteceu a seguir foi resultado de cinco fatores independentes que, combinados, criaram uma tempestade perfeita:

1. A Pipeline Executou sync em Vez de refresh

Após o commit com a reestruturação, a pipeline ContinuousDelivery foi acionada. O mecanismo de sincronização dessa pipeline lista todas as Applications do ArgoCD e força um sync em cada uma delas.

O comportamento adequado nesse cenário teria sido apenas um refresh — que atualiza o estado desejado sem forçar a reconciliação imediata de todos os recursos.

A diferença é crítica:

  • refresh: o ArgoCD atualiza sua visão do estado desejado a partir do Git, mas não força alterações imediatas
  • sync forçado: o ArgoCD aplica imediatamente todas as diferenças entre o estado atual do cluster e o estado desejado no Git

2. Prune Resources e Self Heal Estavam Habilitados

A Application argocd-configuration, responsável por concentrar a configuração do ambiente, estava com as opções Prune Resources e Self Heal habilitadas.

  • Prune Resources: quando um recurso existe no cluster mas não existe mais no Git, o ArgoCD o remove
  • Self Heal: o ArgoCD corrige automaticamente qualquer desvio entre o cluster e o Git

Quando essa Application foi criada inicialmente via script, essas opções não estavam ativas. Até o momento, não há registros que indiquem quando essa configuração foi alterada — um ponto crítico de auditoria.

3. StorageClasses com ReclaimPolicy: Delete

Os drivers de storage do AKS estavam configurados com ReclaimPolicy: Delete. Isso significa que, ao remover um PVC (Persistent Volume Claim), o disco correspondente também é removido do Azure.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-premium
provisioner: disk.csi.azure.com
reclaimPolicy: Delete    # <-- O problema está aqui

Caso estivesse configurado como Retain, o disco permaneceria no Azure mesmo após a exclusão do PVC — sem estar em uso pelo AKS, mas recuperável.

4. O ArgoCD Interpretou a Reestruturação como "Deletar e Recriar"

Aqui está o ponto central do incidente. O comportamento esperado era:

O ArgoCD interpretaria a nova estrutura de pastas no Git como o estado desejado atual do cluster e, portanto, não executaria nenhuma ação destrutiva.

O comportamento observado foi diferente — possivelmente em razão da ordem de processamento interno dos manifestos:

  1. Remoção de todos os recursos anteriormente localizados em cluster-configuration/* — incluindo namespaces, secrets, e demais objetos
  2. Recriação desses mesmos recursos a partir da nova estrutura em cluster-configuration/customer-brasilsouth/

5. A Cascata: Namespace → PVCs → Discos

A remoção do namespace foi o gatilho que desencadeou a exclusão de todos os recursos contidos nele, incluindo os PVCs. E como a ReclaimPolicy era Delete, os discos no Azure foram permanentemente removidos.

Reestruturação de pastas no Git
    └── Pipeline força sync em todas as Applications
        └── ArgoCD com Prune + Self Heal detecta "recursos órfãos"
            └── Remove namespaces antigos
                └── Kubernetes remove todos os recursos do namespace (incluindo PVCs)
                    └── ReclaimPolicy: Delete remove os discos do Azure
                        └── 💥 Dados perdidos

Por Que Isso Aconteceu?

Nenhum dos fatores isoladamente teria causado o incidente. Foi a combinação deles que gerou o cenário destrutivo:

Fator Impacto Isolado Impacto Combinado
Pipeline com forced sync Sincronização agressiva, mas sem efeitos destrutivos se Prune estiver desativado Forçou a reconciliação imediata de todas as mudanças
Prune Resources habilitado Remove recursos órfãos — útil em cenários controlados Instruiu o ArgoCD a deletar recursos que "não existiam mais" no novo caminho
Self Heal habilitado Corrige drift automaticamente — desejável em operação normal Impediu qualquer intervenção manual durante o processo
ReclaimPolicy: Delete Padrão do AKS — limpa discos não utilizados Transformou a exclusão temporária de PVCs em perda permanente de dados
Bug do WebHook (git vs https) Necessidade de pipeline manual como workaround Criou o mecanismo que acionou o sync forçado

A lição mais importante aqui é que sistemas complexos falham de formas complexas. Cada configuração fazia sentido individualmente. Foi a interação entre elas que criou o comportamento destrutivo.

Ações Imediatas

Assim que o incidente foi identificado, as seguintes ações foram tomadas:

  1. Suspensão da pipeline com comportamento inadequado, para que o processo fosse ajustado e passasse a executar refresh em vez de forced sync

  2. Desativação do Prune e Self Heal na Application argocd-configuration — a mais crítica do ambiente — para evitar ações destrutivas automáticas

  3. Criação de novas StorageClasses com ReclaimPolicy: Retain, garantindo que futuros cenários de exclusão de PVCs não resultem na remoção dos discos no Azure:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-premium-retain
provisioner: disk.csi.azure.com
reclaimPolicy: Retain    # Disco permanece no Azure mesmo após exclusão do PVC
  1. Abertura de chamado junto à Microsoft para tentativa de recuperação dos discos removidos

  2. Migração das aplicações para utilização dos novos drivers de storage configurados com ReclaimPolicy: Retain

  3. Desenvolvimento de script de migração de dados para montagem simultânea do PVC antigo e do novo PVC, seguido da sincronização dos arquivos entre ambos — reproduzindo no novo PVC (já com ReclaimPolicy: Retain) o mesmo conteúdo existente no volume anterior

Por Que Ter um Parceiro Azure Faz Toda a Diferença

Aqui entra a parte da história que muitas vezes é subestimada até o momento em que você realmente precisa dela.

O Tempo é Tudo

Quando os discos foram removidos, o relógio começou a contar. A possibilidade de recuperação de discos no Azure depende de ação rápida — e cada minuto de atraso reduz as chances.

Veja a timeline do atendimento a este incidente:

Etapa Horário (GMT-3 Brasília) Tempo decorrido
Abertura do ticket com a INGRAM BRASIL 15:40
Primeira resposta e ação 17:21 1h41min
Resolução do chamado 19:57 4h17min

Pouco mais de 4 horas entre a abertura do chamado e a resolução. Em um cenário de perda de dados em produção, essa velocidade pode ser a diferença entre recuperar tudo e perder tudo.

O Cenário Sem um Parceiro

Já recebemos no passado contatos de empresas que não eram nossos clientes, buscando ajuda desesperadamente em situações críticas:

  • Exclusão acidental de banco de dados em produção
  • Perda de acesso a subscriptions inteiras do Azure
  • Corrupção de dados sem backup recente

Sem um parceiro, o caminho dessas empresas era:

  1. Descobrir que precisam de um plano de suporte do Azure (que não tinham)
  2. Contratar um plano on-demand — processo que leva tempo e burocracia
  3. Abrir o chamado e aguardar o atendimento sem prioridade estabelecida
  4. Tentar explicar todo o contexto do ambiente para um engenheiro que nunca o viu antes

O resultado? Horas ou dias de atraso em situações onde minutos fazem diferença.

O Que um Solutions Partner Oferece

Como Microsoft Solutions Partner — com especialização em 5 das 6 áreas de competência — oferecemos aos nossos clientes:

  • Suporte Premier 24x7: acesso direto a engenheiros Microsoft com SLAs agressivos
  • Relacionamento pré-estabelecido: quando o incidente acontece, não precisamos explicar quem somos ou configurar processos — tudo já está pronto
  • Conhecimento do ambiente: entendemos a arquitetura do cliente, o que acelera drasticamente o diagnóstico
  • Canal direto com distribuidores: a parceria com a INGRAM BRASIL nos permitiu escalar o chamado com velocidade e prioridade

Agradecimento Especial: INGRAM BRASIL

Um agradecimento especial à equipe da INGRAM BRASIL, distribuidora que atua conosco neste cliente e foi fundamental para a resolução rápida deste incidente.

A INGRAM BRASIL foi essencial não apenas na abertura ágil do ticket com a Microsoft, mas em todo o acompanhamento até a resolução. A capacidade de resposta e o comprometimento da equipe demonstram por que ter um ecossistema de parceiros sólido — Partner + Distribuidor + Microsoft — é indispensável para quem roda workloads críticos no Azure.

A diferença entre um incidente e um desastre muitas vezes é o tempo de resposta. E tempo de resposta depende de relacionamentos construídos antes da crise.

Lições Aprendidas

  1. Sempre use ReclaimPolicy: Retain para dados críticos — O padrão Delete é conveniente para ambientes efêmeros, mas em produção, um disco removido pode significar dados irrecuperáveis. Configure Retain e gerencie a limpeza de discos órfãos manualmente ou via automação controlada.

  2. Nunca habilite Prune e Self Heal em Applications críticas sem salvaguardas — Essas opções são poderosas e úteis, mas em Applications que gerenciam a configuração base do cluster, o risco de ações destrutivas automáticas supera os benefícios. Se precisar habilitá-las, implemente políticas de proteção como argocd.argoproj.io/sync-options: Prune=false em recursos sensíveis.

  3. Use refresh em vez de forced sync em pipelines de CI/CD — Um refresh permite que o ArgoCD atualize seu entendimento do estado desejado sem forçar a reconciliação imediata. Isso dá tempo para revisão e intervenção manual quando necessário.

  4. Audite configurações do ArgoCD regularmente — A ativação do Prune e Self Heal na Application crítica aconteceu em algum momento sem registro. Implemente alertas ou políticas (por exemplo, via OPA/Gatekeeper) que detectem mudanças em configurações sensíveis de Applications.

  5. Teste mudanças de infraestrutura em ambientes não produtivos — Reestruturações no repositório Git que afetam o mapeamento de Applications devem ser validadas em um cluster de staging antes de serem aplicadas em produção.

  6. Tenha um Solutions Partner antes de precisar de suporte emergencial — Contratar suporte sob demanda durante uma crise é como tentar fazer seguro depois do acidente. O relacionamento, os processos e os canais de comunicação precisam estar estabelecidos antes do incidente.

  7. Documente todas as mudanças de configuração — A ausência de registros sobre quando o Prune e Self Heal foram habilitados dificultou a análise de causa raiz. Mantenha um changelog auditável para configurações críticas de infraestrutura.

Referências

Kubernetes — Storage e ReclaimPolicy

ArgoCD — Sync e Application Configuration

  • Sync Options — Opções de sincronização incluindo Prune e Self Heal
  • Application Declaration — Especificação de Applications e suas opções de sync policy
  • Webhooks — Configuração de webhooks com provedores Git

Azure — Suporte e Parceiros

Você já passou por um incidente onde a resposta rápida de um parceiro fez a diferença? Ou já enfrentou uma situação crítica no Azure sem suporte adequado? Compartilhe sua experiência nos comentários — histórias reais ajudam toda a comunidade a se preparar melhor.

Confira mais:

Fique por dentro das novidades

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

Assinar gratuitamente