TL;DR — Resumo Rápido

Backup e restauração do etcd no Kubernetes: snapshots, verificação, restauração multi-nó, certificados kubeadm, monitoramento e script de produção.

O etcd é o coração de todo cluster Kubernetes: um armazenamento de chave-valor distribuído e fortemente consistente que guarda o estado completo — desejado e observado — do seu cluster. Quando o etcd está saudável, os comandos kubectl respondem em milissegundos e os controladores reconciliam continuamente. Quando o etcd é perdido sem backup, o cluster desaparece — cada definição de Deployment, cada Secret, cada política RBAC, cada CRD e cada ConfigMap some. Este guia cobre tudo o que você precisa para construir uma estratégia de backup e restauração de etcd de nível produtivo.

Pré-requisitos

  • Um cluster Kubernetes gerenciado com kubeadm (v1.22+) ou acesso aos certificados do etcd
  • etcdctl instalado no nó do plano de controle (a versão deve corresponder à do etcd)
  • Acesso root ou sudo no nó do plano de controle
  • kubectl configurado com permissões de cluster-admin
  • Familiaridade básica com os componentes do plano de controle do Kubernetes
  • Para backups automáticos: acesso a S3, GCS ou armazenamento externo equivalente

O Papel do etcd no Kubernetes

Cada vez que você executa kubectl apply, o API server do Kubernetes valida a requisição e grava o objeto resultante no etcd. Todos os controladores observam o etcd através do mecanismo de watch do API server e reconciliam o cluster de acordo. O etcd é o único componente com estado no plano de controle — todos os outros componentes são stateless e podem ser reiniciados do zero enquanto o etcd estiver intacto.

O que reside no etcd:

  • Todas as definições de objetos da API: Pods, Deployments, StatefulSets, DaemonSets, Services, Ingresses
  • Secrets e ConfigMaps
  • RBAC: Roles, ClusterRoles, RoleBindings, ClusterRoleBindings
  • Custom Resource Definitions e todas as instâncias de recursos personalizados
  • Definições de Namespaces, ResourceQuotas, LimitRanges
  • ServiceAccounts e tokens associados
  • Registros de nós e objetos de lease
  • Registros de eleição de líder para kube-controller-manager e kube-scheduler

O que não reside no etcd: os dados reais armazenados nos PersistentVolumes. O etcd só armazena os objetos PVC e PV (metadados e vinculação), não os bytes em disco.

Arquitetura do etcd: Raft, WAL e Snapshots

O etcd usa o algoritmo de consenso Raft para replicar o estado em um cluster de membros em número ímpar (tipicamente 3 ou 5). O Raft elege um líder que processa todas as escritas; os seguidores replicam o log do líder. O cluster tolera (n-1)/2 falhas de membros — um cluster de 3 nós sobrevive a 1 falha, um de 5 nós sobrevive a 2.

As escritas são primeiro anexadas ao Write-Ahead Log (WAL) em disco e depois aplicadas a uma B-tree em memória (bbolt). Periodicamente, o etcd tira um snapshot interno da B-tree em disco e trunca o WAL para evitar crescimento ilimitado.

O comando etcdctl snapshot save aciona um snapshot do estado atual da B-tree. Esse snapshot é um backup completo e autocontido de todos os dados do etcd no momento em que foi tirado.

Métodos de Backup

Método 1: etcdctl snapshot save (Recomendado)

O método canônico de backup. Em um cluster kubeadm, o etcd roda como pod estático com TLS. Os certificados estão em /etc/kubernetes/pki/etcd/.

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Método 2: CronJob Automatizado

Implante um CronJob do Kubernetes no plano de controle que monte os certificados do etcd do host e grave snapshots em um PVC ou armazenamento em nuvem:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-backup
  namespace: kube-system
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          hostNetwork: true
          containers:
          - name: etcd-backup
            image: bitnami/etcd:3.5
            command:
            - /bin/sh
            - -c
            - |
              ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
                --endpoints=https://127.0.0.1:2379 \
                --cacert=/etc/kubernetes/pki/etcd/ca.crt \
                --cert=/etc/kubernetes/pki/etcd/server.crt \
                --key=/etc/kubernetes/pki/etcd/server.key
            volumeMounts:
            - name: etcd-certs
              mountPath: /etc/kubernetes/pki/etcd
              readOnly: true
            - name: backup-dir
              mountPath: /backup
          volumes:
          - name: etcd-certs
            hostPath:
              path: /etc/kubernetes/pki/etcd
          - name: backup-dir
            persistentVolumeClaim:
              claimName: etcd-backup-pvc
          restartPolicy: OnFailure
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
          - key: node-role.kubernetes.io/control-plane
            effect: NoSchedule

Comparativo de Ferramentas de Backup

FerramentaEstado etcdDados PVGranularidade de RestauraçãoComplexidade
etcdctl snapshotSimNãoCluster completoBaixa
Velero + plugin etcdSimSimNamespace ou completoMédia
etcd-backup-operatorSimNãoCluster completoMédia
kube-backupSimNãoCluster completoBaixa
CronJob manualSimNãoCluster completoBaixa

Verificação do Snapshot

Nunca confie em um backup que você não verificou. Após cada snapshot:

ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db \
  --write-out=table

Se TOTAL KEYS for 0 ou o hash estiver malformado, o snapshot está corrompido. Incorpore a verificação no seu CronJob de backup e configure alertas em caso de falha.

Procedimentos de Restauração

Cluster kubeadm de Um Único Nó

Passo 1: Parar o API server e o etcd

mkdir -p /tmp/k8s-manifests-backup
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/k8s-manifests-backup/
mv /etc/kubernetes/manifests/etcd.yaml /tmp/k8s-manifests-backup/
sleep 10
ps aux | grep etcd

Passo 2: Fazer backup do diretório de dados existente

mv /var/lib/etcd /var/lib/etcd.bak

Passo 3: Restaurar o snapshot

ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --data-dir=/var/lib/etcd \
  --initial-cluster=default=https://127.0.0.1:2380 \
  --initial-cluster-token=etcd-cluster-1 \
  --initial-advertise-peer-urls=https://127.0.0.1:2380

Passo 4: Restaurar os manifests e verificar

mv /tmp/k8s-manifests-backup/etcd.yaml /etc/kubernetes/manifests/
mv /tmp/k8s-manifests-backup/kube-apiserver.yaml /etc/kubernetes/manifests/
sleep 30
kubectl get nodes

Cluster kubeadm Multi-Nó

Para um cluster de 3 nós do plano de controle (HA), você deve restaurar em todos os membros do etcd simultaneamente usando valores consistentes de --initial-cluster e --initial-cluster-token:

# Em cada nó do plano de controle, execute a restauração com o MESMO snapshot e token
# mas com o --name e --initial-advertise-peer-urls corretos para aquele nó

# Nó 1
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --name=etcd-cp1 \
  --data-dir=/var/lib/etcd \
  --initial-cluster=etcd-cp1=https://10.0.0.1:2380,etcd-cp2=https://10.0.0.2:2380,etcd-cp3=https://10.0.0.3:2380 \
  --initial-cluster-token=etcd-restore-token-$(date +%s) \
  --initial-advertise-peer-urls=https://10.0.0.1:2380

Use um --initial-cluster-token único e diferente do original para evitar que o cluster restaurado entre acidentalmente no cluster anterior degradado.

Considerações para Kubernetes Gerenciado

EKS, GKE, AKS — O provedor de nuvem gerencia o etcd internamente. Você não pode acessar o etcd diretamente. Use os mecanismos nativos do provedor:

  • EKS: Velero com S3; a AWS não expõe o etcd diretamente
  • GKE: Velero; o Google gerencia o etcd com backups automáticos no Autopilot
  • AKS: Velero + Azure Blob; a Microsoft gerencia o etcd para node pools gerenciados

Monitoramento da Saúde do etcd

# Verificar saúde do endpoint
ETCDCTL_API=3 etcdctl endpoint health \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

# Verificar líder e status dos membros
ETCDCTL_API=3 etcdctl endpoint status --write-out=table \
  --endpoints=https://10.0.0.1:2379,https://10.0.0.2:2379,https://10.0.0.3:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Alertas Prometheus recomendados para o etcd:

  • etcd_server_has_leader == 0 — sem líder eleito (crítico)
  • etcd_disk_wal_fsync_duration_seconds{quantile="0.99"} > 0.01 — escritas WAL lentas
  • etcd_server_proposals_failed_total > 0 — falhas de consenso
  • etcd_mvcc_db_total_size_in_bytes > 8589934592 — BD próximo do limite de 8 GB

Compactação e Desfragmentação

O etcd mantém um histórico de todas as revisões de chaves. Com o tempo, isso consome espaço em disco significativo. Habilite a compactação automática:

--auto-compaction-mode=periodic
--auto-compaction-retention=1h

Execute a desfragmentação periodicamente durante períodos de baixo tráfego:

ETCDCTL_API=3 etcdctl defrag \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Ajuste de Desempenho

O etcd é extremamente sensível à latência de disco. Recomendações:

  • SSD dedicado: Nunca compartilhe o disco de dados do etcd com cargas de trabalho de aplicações. Use NVMe ou SSD com IOPS de escrita aleatória sustentada > 2000.
  • Timeouts de heartbeat e eleição: O heartbeat-interval padrão é 100ms e o election-timeout é 1000ms. Em ambientes de alta latência, aumente para 250ms / 1250ms.
  • Cota de BD: O padrão é 2 GB. Aumente para 8 GB em clusters grandes: --quota-backend-bytes=8589934592

Script de Backup de Produção com Alertas

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/etcd-backups"
RETENTION_COUNT=24
S3_BUCKET="s3://meu-cluster-etcd-backups"
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"
ETCD_ENDPOINTS="https://127.0.0.1:2379"
CACERT="/etc/kubernetes/pki/etcd/ca.crt"
CERT="/etc/kubernetes/pki/etcd/server.crt"
KEY="/etc/kubernetes/pki/etcd/server.key"

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
SNAPSHOT_FILE="${BACKUP_DIR}/etcd-${TIMESTAMP}.db"

alerta() {
  local msg="$1"
  curl -s -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"[etcd-backup] ${msg}\"}" "${SLACK_WEBHOOK}" || true
}

mkdir -p "${BACKUP_DIR}"

if ! ETCDCTL_API=3 etcdctl snapshot save "${SNAPSHOT_FILE}" \
    --endpoints="${ETCD_ENDPOINTS}" \
    --cacert="${CACERT}" --cert="${CERT}" --key="${KEY}"; then
  alerta "CRÍTICO: etcd snapshot save FALHOU em $(hostname) às ${TIMESTAMP}"
  exit 1
fi

KEYS=$(ETCDCTL_API=3 etcdctl snapshot status "${SNAPSHOT_FILE}" \
  --write-out=json | python3 -c "import sys,json; print(json.load(sys.stdin)['totalKey'])")
if [ "${KEYS}" -lt 100 ]; then
  alerta "AVISO: snapshot tem apenas ${KEYS} chaves — possível snapshot vazio ou corrompido"
  exit 1
fi

aws s3 cp "${SNAPSHOT_FILE}" "${S3_BUCKET}/$(basename ${SNAPSHOT_FILE})" \
  --storage-class STANDARD_IA

ls -t "${BACKUP_DIR}"/etcd-*.db | tail -n +$((RETENTION_COUNT + 1)) | xargs -r rm -f

echo "Backup concluído: ${SNAPSHOT_FILE} (${KEYS} chaves)"

Cenários de Recuperação de Desastres

Cenário 1: Falha de um membro (quórum intacto) — O cluster continua operando. Substitua o membro com falha usando etcdctl member remove + etcdctl member add sem necessidade de restauração.

Cenário 2: Perda de quórum (maioria dos membros fora) — O cluster se torna somente leitura. Se os dados estiverem intactos, restaure a conectividade. Se os dados foram perdidos, restaure a partir do snapshot em todos os membros.

Cenário 3: Restauração completa do cluster — Pare todos os componentes do plano de controle, restaure o snapshot em cada nó com --initial-cluster-token consistente, reinicie na ordem: etcd primeiro, depois kube-apiserver, depois kube-controller-manager e kube-scheduler.

Casos Especiais e Erros Comuns

Incompatibilidade de versão do etcdctl — Sempre defina ETCDCTL_API=3. Verifique se a versão do cliente corresponde à do servidor. Incompatibilidades causam falhas silenciosas ou restaurações corrompidas.

A restauração sobrescreve o diretório de dadosetcdctl snapshot restore escreve em --data-dir. Se o diretório já existir, a restauração falha. Sempre mova o diretório existente antes.

Desvio de relógio entre membros — Os certificados TLS dos pares do etcd são sensíveis ao tempo. Certifique-se de que o NTP esteja configurado e sincronizado em todos os nós do plano de controle.

Surpresas em clusters gerenciados — No GKE ou EKS, tentar executar no pod do etcd falhará ou será bloqueado. Se você está em um cluster gerenciado, use Velero imediatamente.

Resumo

  • O etcd armazena todo o estado do cluster Kubernetes; perdê-lo sem backup significa reconstruir do zero
  • Use etcdctl snapshot save com flags TLS apontando para /etc/kubernetes/pki/etcd/ em clusters kubeadm
  • Sempre execute etcdctl snapshot status para verificar snapshots após a criação
  • A restauração requer parar o API server e o etcd, executar etcdctl snapshot restore e reiniciar o plano de controle
  • A restauração multi-nó requer --initial-cluster-token consistente e --initial-advertise-peer-urls corretos por nó
  • Habilite a compactação automática e execute etcdctl defrag mensalmente
  • Dedique um SSD de baixa latência aos dados do etcd; monitore a latência de WAL fsync com Prometheus
  • Armazene snapshots externamente (S3/GCS) com pelo menos 24h de retenção; automatize com CronJob + script de alertas

Artigos Relacionados