<h2>Entendendo Disaster Recovery em Kubernetes</h2>
<p>Disaster Recovery (DR) é a capacidade de recuperar sua infraestrutura e dados após um evento catastrófico. Em ambientes Kubernetes, isso vai muito além de fazer backup de um banco de dados — você precisa proteger toda a configuração do cluster, volumes persistentes, secrets, ConfigMaps, objetos personalizados e o estado da aplicação. A realidade é que perder um cluster inteiro ou ter dados corrompidos é mais comum do que gostaríamos de admitir, especialmente em ambientes de produção.</p>
<p>O desafio aumenta porque Kubernetes é distribuído e stateless por design. Seus deployments, services e ingresses são efêmeros. Quando você perde um cluster, perde toda essa declaração e o estado das aplicações. É por isso que uma estratégia de DR bem pensada não apenas salva seus dados, mas também permite reconstruir o cluster inteiro em outro lugar, com a mesma configuração e estado. Vamos explorar como o Velero resolve isso de forma elegante e prática.</p>
<h2>O que é Velero e como funciona</h2>
<p>O Velero é uma ferramenta open-source mantida pela comunidade Kubernetes que automatiza backup e restore de clusters Kubernetes. Ele funciona criando snapshots de todo o seu cluster — recursos, volumes persistentes, namespaces, e até mesmo objetos customizados — e os armazena em um storage externo como Amazon S3, Google Cloud Storage ou MinIO.</p>
<p>A arquitetura do Velero é baseada em dois componentes principais: um servidor que roda dentro do cluster (como um Deployment) e a CLI que você usa para interagir com ele. Quando você inicia um backup, o servidor Velero lê todos os recursos do cluster através da API Kubernetes, serializa-os em formato JSON, e envia para o storage backend. Para volumes persistentes, ele usa plugins específicos que conseguem fazer snapshots do storage subjacente (EBS, GCP Persistent Disks, ou cria backups dinâmicos através de restic). No restore, o processo é invertido: ele lê os dados do storage, recria os recursos na ordem correta e restaura os volumes.</p>
<p>O ponto crucial é que Velero entende a semântica dos seus recursos. Ele não faz apenas cópia byte-a-byte. Ele sabe que um Deployment precisa ser criado antes de um Pod, que um ConfigMap pode ser referenciado por múltiplos Deployments, e que certos recursos como Nodes não devem ser restaurados (pois o cluster-alvo terá seus próprios Nodes). Isso permite recuperação inteligente e sem conflitos.</p>
<h3>Arquitetura e fluxo de backup</h3>
<p>O backup no Velero funciona através de um modelo push onde o servidor dentro do cluster coleta recursos, aplica filtros e transformações, e envia tudo para um backend de armazenamento. O pipeline é composto por hooks (que podem executar comandos antes/depois do backup), filtros de recursos (você escolhe o que fazer backup), e drivers de plugin para diferentes tipos de storage.</p>
<pre><code class="language-yaml"># Exemplo de um Backup customizado no Velero
apiVersion: velero.io/v1
kind: Backup
metadata:
name: my-cluster-backup
namespace: velero
spec:
Define o TTL antes de deletar automaticamente
ttl: 720h
Inclui esses namespaces
includedNamespaces:
- production
- staging
Exclui recursos específicos
excludedResources:
- nodes
- events
Incluir volumes persistentes
storageLocation: default
Hook para pausar aplicação antes do backup
hooks:
resources:
- name: pause-app
includedNamespaces:
- production
pre:
- exec:
container: "app-container"
command: ["/bin/sh", "-c", "kill -SIGSTOP 1"]</code></pre>
<p>Este manifesto define um backup que inclui apenas namespaces de produção e staging, exclui Nodes e Events (que não faz sentido restaurar), e executa um comando para pausar a aplicação antes do snapshot. Essa abordagem garante consistência dos dados.</p>
<h3>Armazenamento e retenção</h3>
<p>O Velero precisa de um backend de armazenamento externo ao cluster. Os principais são Amazon S3, Google Cloud Storage, Microsoft Azure Blob Storage, e qualquer storage S3-compatível como MinIO. Você configura a credencial e o bucket uma única vez, e todos os backups vão para lá.</p>
<pre><code class="language-yaml"># Exemplo de configuração de storage backend (Secret + BackupStorageLocation)
apiVersion: v1
kind: Secret
metadata:
name: velero-aws-credentials
namespace: velero
type: Opaque
data:
Base64 encoded AWS credentials
cloud: W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkID0gQUtJQVhYWFhYWFhYWFhYWFhYCmF3c19zZWNyZXRfYWNjZXNzX2tleSA9IHlkKzZhK3hYWFhYWFhYWFhY=
---
apiVersion: velero.io/v1
kind: BackupStorageLocation
metadata:
name: default
namespace: velero
spec:
provider: aws
bucket: my-velero-backups
config:
region: us-east-1
s3Url: https://s3.amazonaws.com
credential:
name: velero-aws-credentials
key: cloud
Retenção automática após 30 dias
accessMode: ReadWrite</code></pre>
<p>A retenção é crucial em DR. Você não quer guardar backups antigos indefinidamente (custa dinheiro) nem quer deletar muito rápido (precisa de histórico). O Velero permite definir TTL (Time To Live) por backup ou por política, garantindo limpeza automática.</p>
<h2>Instalação e Configuração Prática</h2>
<p>Para começar com Velero, você precisa ter um cluster Kubernetes rodando e acesso ao kubectl. A instalação envolve adicionar o repositório Helm, configurar credenciais para o storage backend, e fazer deploy do Velero.</p>
<h3>Instalação via Helm</h3>
<pre><code class="language-bash"># Adicionar o repositório Helm do Velero
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm repo update
Criar namespace
kubectl create namespace velero
Criar arquivo com credenciais AWS (se usando S3)
cat > credentials-velero <<EOF
[default]
aws_access_key_id = YOUR_AWS_ACCESS_KEY
aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
EOF
Instalar Velero com configuração para AWS S3
helm install velero vmware-tanzu/velero \
--namespace velero \
--set configuration.backupStorageLocation.bucket=my-velero-backups \
--set configuration.backupStorageLocation.provider=aws \
--set configuration.backupStorageLocation.config.region=us-east-1 \
--set configuration.schedules.daily.schedule="0 2 *" \
--set configuration.schedules.daily.template.ttl=720h \
--set credentials.useSecret=true \
--set-file credentials.extraSecret=./credentials-velero</code></pre>
<p>Este comando instala o Velero configurado para fazer backup em um bucket S3 todo dia às 2 da manhã, mantendo backups por 30 dias. O Velero vai criar um Deployment com os controladores necessários, um CronJob para backups agendados, e um serviço para expor a API.</p>
<h3>Instalação manual com manifests</h3>
<p>Se preferir mais controle, você pode usar os manifests YAML diretamente:</p>
<pre><code class="language-bash"># Fazer download dos manifests
kubectl apply -f https://github.com/vmware-tanzu/velero/releases/download/v1.12.0/velero-v1.12.0-kubernetes.tar.gz
Isso instala:
- CRDs (Custom Resource Definitions)
- Namespace velero
- RBAC (ServiceAccount, ClusterRole, ClusterRoleBinding)
- Deployment do servidor Velero
- ConfigMap com configuração</code></pre>
<p>Depois você precisa editar o ConfigMap para adicionar suas credenciais e informações de storage. A abordagem manual é mais verbosa, mas oferece visibilidade total.</p>
<h3>Verificação da instalação</h3>
<pre><code class="language-bash"># Verificar se o Velero está rodando
kubectl get deployment -n velero
Ver logs do servidor
kubectl logs -n velero -l app.kubernetes.io/name=velero -f
Testar conectividade com o storage
velero backup-location get
Saída esperada:
NAME PROVIDER BUCKET/CONTAINER PHASE LAST VALIDATED
default aws my-velero-backups Available 2024-01-15T10:30:00Z</code></pre>
<p>Se o PHASE for "Available", você está conectado corretamente ao storage.</p>
<h2>Criando Backups: Estratégia e Implementação</h2>
<p>Existem duas abordagens para criar backups: sob demanda (manual) e agendados (automáticos). A estratégia ideal combina ambas — backups automáticos diários para recuperação rápida e backups manuais antes de operações críticas como upgrades ou mudanças arquiteturais.</p>
<h3>Backup sob demanda</h3>
<p>Um backup manual é perfeito para antes de uma mudança arriscada. Você cria, valida, e só depois procede:</p>
<pre><code class="language-bash"># Criar um backup imediato de todo o cluster
velero backup create full-cluster-backup-$(date +%Y%m%d-%H%M%S)
Criar backup apenas de um namespace específico
velero backup create production-backup --include-namespaces production
Criar backup excluindo namespaces do sistema
velero backup create app-backup \
--exclude-namespaces kube-system,kube-public,velero \
--wait
Listar todos os backups
velero backup get
Ver detalhes de um backup específico
velero backup describe full-cluster-backup-20240115-143022 --details
Ver logs de um backup (útil para debugar)
velero backup logs full-cluster-backup-20240115-143022</code></pre>
<p>O <code>--wait</code> faz o comando bloquear até o backup terminar. Para operações grandes, isso pode levar minutos. Sem ele, o comando retorna imediatamente e você pode monitorar com <code>describe</code>.</p>
<h3>Backups agendados</h3>
<p>Para operações contínuas, você configura um schedule no Velero que cria backups automaticamente:</p>
<pre><code class="language-yaml"># Exemplo de Schedule - backup diário
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: daily-backup
namespace: velero
spec:
Executa todo dia às 2 da manhã
schedule: "0 2 *"
template:
includedNamespaces:
- "*"
excludedNamespaces:
- kube-system
- kube-node-lease
- kube-public
- velero
storageLocation: default
Backup automático de volumes
defaultVolumesToFsBackup: true
Retenção de 30 dias
ttl: 720h
---
Schedule para backup semanal completo
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: weekly-full-backup
namespace: velero
spec:
Executa todo domingo às 3 da manhã
schedule: "0 3 0"
template:
includedNamespaces:
- "*"
excludedNamespaces:
- velero
storageLocation: default
defaultVolumesToFsBackup: true
Retenção de 90 dias para backups semanais
ttl: 2160h</code></pre>
<p>Crie esses recursos com <code>kubectl apply -f schedule.yaml</code>. O Velero criará um CronJob que dispara backups nos horários especificados. A sintaxe é padrão cron: minuto, hora, dia do mês, mês, dia da semana.</p>
<h3>Monitorando backups</h3>
<pre><code class="language-bash"># Ver o progresso de um backup em tempo real
watch -n 5 "velero backup describe full-cluster-backup-20240115-143022"
Ou verificar via kubectl
kubectl get backups -n velero -o wide
Saída:
NAME STATUS ERRORS WARNINGS CREATED EXPIRES
full-cluster-backup-20240115-143022 Completed 0 0 2024-01-15T14:30:22Z 2024-02-14T14:30:22Z</code></pre>
<p>Um STATUS de "Completed" com 0 errors significa sucesso. "Warnings" indicam pequenos problemas (um recurso que não pôde ser copiado, por exemplo) mas o backup continuou. Se ver "Failed", verifique os logs.</p>
<h3>Hooks para consistência</h3>
<p>Para aplicações stateful, você pode querer pausar operações durante o backup:</p>
<pre><code class="language-yaml">apiVersion: velero.io/v1
kind: Backup
metadata:
name: mysql-consistent-backup
namespace: velero
spec:
includedNamespaces:
- databases
hooks:
resources:
- name: mysql-backup-hook
includedNamespaces:
- databases
includedResources:
- pods
labelSelector:
matchLabels:
app: mysql
pre:
Executar FLUSH TABLES WITH READ LOCK antes do backup
- exec:
container: mysql
command: ["/bin/bash", "-c", "mysql -uroot -p$MYSQL_ROOT_PASSWORD -e 'FLUSH TABLES WITH READ LOCK;'"]
onError: Fail
timeout: 30s
post:
Liberar lock após backup
- exec:
container: mysql
command: ["/bin/bash", "-c", "mysql -uroot -p$MYSQL_ROOT_PASSWORD -e 'UNLOCK TABLES;'"]
onError: Warn
timeout: 30s</code></pre>
<p>Os hooks de <code>pre</code> executam antes do backup (para preparar a aplicação), e <code>post</code> após (para limpeza). Use <code>onError: Fail</code> para hooks críticos e <code>onError: Warn</code> para opcionais.</p>
<h2>Restauração e Testes de DR</h2>
<p>Fazer backup é apenas metade do trabalho. A verdadeira medida de uma estratégia de DR é se você consegue restaurar rapidamente quando precisa. Por isso é crucial testar restaurações regularmente — não apenas deixar backups acumulando.</p>
<h3>Restore completo em um novo cluster</h3>
<p>Este é o cenário de disaster total: seu cluster foi destruído e você precisa reconstruir em outro lugar:</p>
<pre><code class="language-bash"># Listar todos os backups disponíveis
velero backup get
Restaurar um backup completo
velero restore create --from-backup full-cluster-backup-20240115-143022 --wait
Monitorar progresso
velero restore describe full-cluster-backup-20240115-143022-<timestamp>
Ou via kubectl
kubectl get restores -n velero -o wide</code></pre>
<p>Quando você restaura em um novo cluster, o Velero recria todos os Deployments, Services, ConfigMaps, Secrets, Volumes — tudo. A única coisa que ele não restaura são os Nodes (o novo cluster já tem seus próprios). Dependendo do tamanho do cluster, isso pode levar de minutos a horas.</p>
<h3>Restore seletivo de namespace</h3>
<p>Frequentemente você não quer restaurar o cluster inteiro, apenas um aplicativo específico:</p>
<pre><code class="language-bash"># Restaurar apenas o namespace 'production'
velero restore create \
--from-backup full-cluster-backup-20240115-143022 \
--include-namespaces production \
--wait
Restaurar múltiplos namespaces
velero restore create \
--from-backup full-cluster-backup-20240115-143022 \
--include-namespaces production,staging \
--wait
Restaurar tudo EXCETO certos namespaces
velero restore create \
--from-backup full-cluster-backup-20240115-143022 \
--exclude-namespaces kube-system,velero \
--wait</code></pre>
<p>Isso é útil quando há corrupção apenas em uma parte do cluster. Você isola o problema e restaura apenas aquela seção.</p>
<h3>Restore com transformações</h3>
<p>Às vezes você quer restaurar para um ambiente diferente (ex: produção → staging). Você pode aplicar transformações:</p>
<pre><code class="language-yaml"># Exemplo de Policy que renomeia namespaces durante restore
apiVersion: velero.io/v1
kind: RestoreItemActionTemplate
metadata:
name: change-storage-class
namespace: velero
spec:
resourceIncludeString: "persistentvolumeclaims"
action: |
$patch = [{"op":"replace","path":"/spec/storageClassName","value":"fast-ssd"}]
$patchType = "JSONPatch"
---
Aplicar a transformação durante restore
velero restore create \
--from-backup production-backup \
--include-namespaces production \
--restore-volumes=true \
--wait</code></pre>
<p>Você também pode usar um RestoreItemAction custom (em Go) para transformações mais complexas, como alterar domínios em Ingress ou mudar variáveis de ambiente.</p>
<h3>Teste periódico de restore</h3>
<p>Uma estratégia recomendada é fazer um "restore test" regularmente em um cluster separado:</p>
<pre><code class="language-bash">#!/bin/bash
Script para testar restore semanalmente
Encontrar o backup mais recente
LATEST_BACKUP=$(velero backup get --sort-by='.metadata.creationTimestamp' -o json | jq -r '.items[-1].metadata.name')
echo "Testing restore from backup: $LATEST_BACKUP"
Criar namespace de teste
kubectl create namespace dr-test
Restaurar para namespace de teste
velero restore create \
--from-backup "$LATEST_BACKUP" \
--include-namespaces production \
--namespace-mappings production=dr-test \
--wait
Aguardar estabilização
sleep 30
Verificar que os pods estão rodando
RUNNING=$(kubectl get pods -n dr-test -o json | jq '.items[] | select(.status.phase=="Running") | .metadata.name' | wc -l)
echo "Running pods in dr-test: $RUNNING"
Rodar testes de saúde
kubectl run -n dr-test smoke-test --image=curlimages/curl --rm -it -- \
curl -s http://app-service:8080/health | jq .
Limpar
kubectl delete namespace dr-test
echo "DR test completed"</code></pre>
<p>Execute isso semanalmente em um ambiente de teste. Se o restore falha em teste, você saberá antes que precisar fazer para real.</p>
<h3>Verificando a integridade do restore</h3>
<pre><code class="language-bash"># Após restaurar, verificar que todos os recursos foram criados
velero restore describe <restore-name> --details
Contar recursos por tipo
kubectl get all -A | tail -20
Verificar que volumes foram restaurados
kubectl get pvc -A
Testar conectividade de uma aplicação restaurada
POD=$(kubectl get pods -n <namespace> -l app=myapp -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD -n <namespace> -- /bin/sh
Dentro do pod, verificar que dados persistentes estão presentes
ls -la /data/
cat /data/important-file.txt</code></pre>
<p>Se tudo estiver em ordem, seus backups são confiáveis.</p>
<h2>Casos Avançados e Troubleshooting</h2>
<p>Nem todo cenário é simples. Às vezes você enfrenta clusters gigantes, aplicações com estado complexo, ou erros durante backup/restore. Vamos cobrir os problemas mais comuns.</p>
<h3>Exclusões inteligentes</h3>
<p>Nem tudo precisa (ou deveria) ser feito backup:</p>
<pre><code class="language-yaml">apiVersion: velero.io/v1
kind: Backup
metadata:
name: smart-backup
namespace: velero
spec:
includedNamespaces:
- "*"
excludedNamespaces:
- kube-system
- kube-node-lease
- kube-public
- velero
excludedResources:
Não fazer backup desses tipos de recurso
- nodes
- events
- events.events.k8s.io
- backups.velero.io
- restores.velero.io
- resticrepositories.velero.io
- csinodes.storage.k8s.io
- csidrivers.storage.k8s.io
- csistoragecapacities.storage.k8s.io
Também pode excluir recursos por label
labelSelector:
matchExpressions:
- key: backup
operator: NotIn
values:
- "false"</code></pre>
<p>A regra de ouro: não faça backup de dados que podem ser recriados (caches, índices, logs) ou que são infraestrutura do cluster (Nodes, componentes do kube-system).</p>
<h3>Debugando falhas de backup</h3>
<pre><code class="language-bash"># Ver logs detalhados do servidor Velero
kubectl logs -n velero -l app.kubernetes.io/name=velero --tail=200
Ver logs específicos de um backup
velero backup logs <backup-name>
Descrever backup com todos os erros
velero backup describe <backup-name> --details
Aumentar nível de verbosidade
kubectl set env deployment/velero -n velero LOG_LEVEL=debug
kubectl logs -n velero -l app.kubernetes.io/name=velero -f</code></pre>
<p>Erros comuns incluem: credenciais inválidas (não consegue escrever no S3), volumes usando storage classes não suportadas, ou aplicações que não permitem snapshots.</p>
<h3>Otimizando backups grandes</h3>
<p>Para clusters com centenas de GB de dados:</p>
<pre><code class="language-yaml">apiVersion: velero.io/v1
kind: Backup
metadata:
name: optimized-backup
namespace: velero
spec:
includedNamespaces:
- production
Usar compressão
snapshotMoveData: true
Tirar snapshots paralelos
parallelFilesUpload: 10
Aumentar chunk size para volumes grandes
defaultVolumesToFsBackup: true
fsBackupTimeout: 1h</code></pre>
<p>Também considere:</p>
<pre><code class="language-bash"># Fazer backups incrementais (apenas mudanças desde o último)
Isso é suportado nativamente pelo Velero em volumes que usam restic
Para storage dinâmico, configure restic:
kubectl set env deployment/velero -n velero RESTIC_PRUNE_FREQUENCY=weekly</code></pre>
<h3>Restauração seletiva por label</h3>
<pre><code class="language-bash"># Restaurar apenas recursos com label 'tier=critical'
velero restore create \
--from-backup full-backup \
--selector "tier=critical" \
--wait
Restaurar tudo EXCETO o que tem label 'tier=temporary'
velero restore create \
--from-backup full-backup \
--exclude-resources "pods" \
--wait</code></pre>
<p>Use labels estrategicamente para categorizar seus recursos. Isso permite restaurações granulares.</p>
<h3>Migração entre clusters</h3>
<p>Um use case poderoso é migração para um novo cluster (upgrade de versão, mudar cloud provider, etc.):</p>
<pre><code class="language-bash"># Cluster antigo: fazer backup final
velero backup create migration-backup-$(date +%s)
Copiar credenciais do storage para o novo cluster
(o novo cluster precisa acesso ao mesmo S3 bucket)
Novo cluster: instalar Velero apontando para mesmo storage
(usar mesmo bucket, mesma região, mesmas credenciais)
Novo cluster: restaurar
velero restore create --from-backup migration-backup-<timestamp> --wait
Verificar que tudo foi restaurado
kubectl get ns
kubectl get all -A</code></pre>
<p>O Velero faz essa migração ser trivial. Você não precisa fazer <code>kubectl drain</code> manualmente ou mexer em volumes.</p>
<h2>Conclusão</h2>
<p>Aprendemos que Disaster Recovery em Kubernetes requer uma abordagem sistemática onde o Velero é a ferramenta central. Os três pontos principais são: <strong>primeiro, backup não é útil sem restore</strong> — você deve testar regularmente que consegue restaurar rapidamente, idealmente em ambientes separados. <strong>Segundo, estratégia de retenção importa</strong> — backups muito antigos custam dinheiro e backups deletados muito rápido deixam você sem opções. Combine backups diários com retenção de semanas, backups semanais com retenção de meses. <strong>Terceiro, uma boa DR strategy é incrementalista</strong> — comece protegendo apenas dados críticos, estenda para aplicações inteiras, eventualmente backup completo do cluster. Não tente fazer tudo de uma vez; implemente, teste, valide, depois expanda.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://velero.io/docs/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Velero</a></li>
<li><a href="https://github.com/vmware-tanzu/velero" target="_blank" rel="noopener noreferrer">Velero GitHub Repository</a></li>
<li><a href="https://kubernetes.io/docs/tasks/administer-cluster/disaster-recovery/" target="_blank" rel="noopener noreferrer">Kubernetes Disaster Recovery Best Practices</a></li>
<li><a href="https://github.com/vmware-tanzu/helm-charts/tree/main/charts/velero" target="_blank" rel="noopener noreferrer">Velero Helm Chart Documentation</a></li>
<li><a href="https://velero.io/docs/main/custom-resources/" target="_blank" rel="noopener noreferrer">Velero Plugins for Storage Providers</a></li>
</ul>
<p><!-- FIM --></p>