O etcd é o armazenamento distribuído de chave-valor no coração de cada cluster Kubernetes, armazenando todo o estado do cluster, desde definições de pods até secrets. Quando o etcd fica indisponível ou perde dados, todo o plano de controle para de funcionar. Este guia orienta você na implantação do etcd como um serviço standalone e como um cluster de três nós, na proteção com TLS mútuo, na criação e restauração de snapshots, e no entendimento de como o Kubernetes o utiliza — para que você possa operá-lo com confiança em produção.

Pré-requisitos

  • Servidor(es) Linux executando Ubuntu 22.04 ou posterior (um para nó único, três para cluster)
  • Acesso root ou sudo
  • Familiaridade básica com gerenciamento de serviços systemd
  • curl e tar instalados
  • Para TLS: cfssl ou openssl disponíveis
  • Portas 2379 (cliente) e 2380 (peer) abertas entre os nós etcd

O Que É o etcd e Como Funciona

O etcd é um armazenamento distribuído de chave-valor de código aberto e altamente consistente, originalmente desenvolvido pela CoreOS e agora um projeto graduado da Cloud Native Computing Foundation (CNCF). Ele usa o algoritmo de consenso Raft para garantir que todos os nós concordem com o estado atual, mesmo quando ocorrem partições de rede ou falhas de nós.

As propriedades principais que você precisa entender:

  • Consistência forte: cada leitura retorna a última gravação confirmada, nunca um valor desatualizado
  • Watch API: os clientes assinam alterações de chave e recebem notificações em tempo real
  • Transações atômicas: operações de compare-and-swap permitem construir bloqueios distribuídos
  • Leases: as chaves podem expirar automaticamente, habilitando a eleição de líderes baseada em heartbeat

O Kubernetes depende do etcd para cada parte do estado do cluster. O servidor de API é o único componente que lê e grava no etcd diretamente — todos os outros componentes (scheduler, controller manager, kubelet) se comunicam através do servidor de API.

FuncionalidadeetcdRedisConsulZooKeeper
ConsensoRaftNenhum (standalone)RaftZAB
Consistência forteSimNão (eventual)SimSim
Watch APISimApenas pub/subSimSim
Nativo do KubernetesSimNãoNãoNão
TLS integradoSimOpcionalSimOpcional
Complexidade operacionalBaixaMuito baixaMédiaAlta

O etcd se destaca para o Kubernetes porque foi desenvolvido especificamente para casos de uso de plano de controle: valores pequenos, alta taxa de leitura, gravações pouco frequentes e correção em detrimento do throughput bruto.

Instalando o etcd

Baixe a versão mais recente do repositório oficial do GitHub. No momento da escrita, a série 3.5.x é a série estável recomendada para Kubernetes 1.29+.

ETCD_VER=v3.5.12
DOWNLOAD_URL=https://github.com/etcd-io/etcd/releases/download

curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz \
  -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz

tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/

sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcd /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdutl /usr/local/bin/

etcd --version
etcdctl version

Crie o diretório de dados e um usuário de sistema dedicado:

sudo groupadd --system etcd
sudo useradd -s /sbin/nologin --system -g etcd etcd
sudo mkdir -p /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd
sudo chmod 700 /var/lib/etcd

Gerando Certificados TLS

Nunca execute o etcd sem TLS em qualquer ambiente além de um laptop local. O etcd armazena secrets e credenciais — qualquer listener não criptografado representa um risco imediato de segurança.

Instale o cfssl:

curl -Lo /usr/local/bin/cfssl \
  https://github.com/cloudflare/cfssl/releases/latest/download/cfssl_linux-amd64
curl -Lo /usr/local/bin/cfssljson \
  https://github.com/cloudflare/cfssl/releases/latest/download/cfssljson_linux-amd64
chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson

Crie uma CA e um certificado de servidor. Salve o seguinte como ca-config.json:

{
  "signing": {
    "default": { "expiry": "87600h" },
    "profiles": {
      "etcd": {
        "expiry": "87600h",
        "usages": ["signing","key encipherment","server auth","client auth"]
      }
    }
  }
}

Gere os certificados de CA e servidor:

# CA
cfssl gencert -initca ca-csr.json | cfssljson -bare ca

# Certificado de servidor + peer (adicione todos os IPs/hostnames dos nós no array hosts do CSR)
cfssl gencert \
  -ca=ca.pem -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=etcd \
  etcd-csr.json | cfssljson -bare etcd

sudo mkdir -p /etc/etcd/pki
sudo cp ca.pem etcd.pem etcd-key.pem /etc/etcd/pki/
sudo chown -R etcd:etcd /etc/etcd/pki
sudo chmod 600 /etc/etcd/pki/*-key.pem

Configurando um Cluster etcd de Três Nós

Um cluster etcd de produção precisa de três ou cinco membros. Com três membros, ele tolera uma falha e ainda mantém o quórum. Com cinco, tolera duas falhas simultâneas.

Considere três nós com os seguintes IPs:

  • etcd-1: 10.0.0.11
  • etcd-2: 10.0.0.12
  • etcd-3: 10.0.0.13

Crie /etc/etcd/etcd.conf.yml em cada nó, substituindo os valores específicos do nó:

# /etc/etcd/etcd.conf.yml — exemplo para etcd-1
name: etcd-1
data-dir: /var/lib/etcd

listen-peer-urls: https://10.0.0.11:2380
listen-client-urls: https://10.0.0.11:2379,https://127.0.0.1:2379

advertise-client-urls: https://10.0.0.11:2379
initial-advertise-peer-urls: https://10.0.0.11:2380

initial-cluster: >-
  etcd-1=https://10.0.0.11:2380,
  etcd-2=https://10.0.0.12:2380,
  etcd-3=https://10.0.0.13:2380
initial-cluster-token: etcd-cluster-prod-01
initial-cluster-state: new

client-transport-security:
  cert-file: /etc/etcd/pki/etcd.pem
  key-file: /etc/etcd/pki/etcd-key.pem
  trusted-ca-file: /etc/etcd/pki/ca.pem
  client-cert-auth: true

peer-transport-security:
  cert-file: /etc/etcd/pki/etcd.pem
  key-file: /etc/etcd/pki/etcd-key.pem
  trusted-ca-file: /etc/etcd/pki/ca.pem
  peer-client-cert-auth: true

Crie a unidade systemd /etc/systemd/system/etcd.service em todos os nós:

[Unit]
Description=etcd distributed key-value store
Documentation=https://etcd.io
After=network.target

[Service]
User=etcd
Group=etcd
Type=notify
ExecStart=/usr/local/bin/etcd --config-file /etc/etcd/etcd.conf.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Inicie o cluster — todos os três nós devem iniciar dentro do timeout de eleição (padrão 1 segundo) para que o bootstrap inicial seja bem-sucedido:

# Execute em todos os três nós em rápida sucessão
sudo systemctl daemon-reload
sudo systemctl enable --now etcd

Verifique se o cluster foi formado corretamente:

export ETCDCTL_API=3
export ETCDCTL_ENDPOINTS=https://10.0.0.11:2379,https://10.0.0.12:2379,https://10.0.0.13:2379
export ETCDCTL_CACERT=/etc/etcd/pki/ca.pem
export ETCDCTL_CERT=/etc/etcd/pki/etcd.pem
export ETCDCTL_KEY=/etc/etcd/pki/etcd-key.pem

etcdctl endpoint health
etcdctl endpoint status --write-out=table
etcdctl member list --write-out=table

Backup e Restauração de Snapshot do etcd

O backup do etcd é obrigatório em produção. Um snapshot captura todo o armazenamento de chave-valor em um determinado momento. Sempre faça backup antes de atualizar o etcd ou o Kubernetes.

Tirando um Snapshot

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

# Verificar o snapshot
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot-*.db --write-out=table

Automatize com um cron job que rotaciona snapshots antigos:

# /etc/cron.d/etcd-backup
0 2 * * * etcd /usr/local/bin/etcdctl snapshot save \
  /backup/etcd-$(date +\%Y\%m\%d).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/pki/ca.pem \
  --cert=/etc/etcd/pki/etcd.pem \
  --key=/etc/etcd/pki/etcd-key.pem && \
  find /backup/ -name "etcd-*.db" -mtime +7 -delete

Restaurando a Partir de um Snapshot

A restauração substitui o diretório de dados. Execute isso em cada membro do cluster:

# 1. Pare o etcd em TODOS os nós primeiro
sudo systemctl stop etcd

# 2. Restaure em cada nó (use um --name e --initial-advertise-peer-urls únicos por nó)
ETCDCTL_API=3 etcdutl snapshot restore /backup/etcd-snapshot.db \
  --name etcd-1 \
  --initial-cluster "etcd-1=https://10.0.0.11:2380,etcd-2=https://10.0.0.12:2380,etcd-3=https://10.0.0.13:2380" \
  --initial-cluster-token etcd-cluster-prod-01 \
  --initial-advertise-peer-urls https://10.0.0.11:2380 \
  --data-dir /var/lib/etcd-restored

# 3. Troque o diretório de dados
sudo mv /var/lib/etcd /var/lib/etcd-old
sudo mv /var/lib/etcd-restored /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd

# 4. Inicie o etcd em TODOS os nós
sudo systemctl start etcd

Cenário Real: Recuperando um Plano de Controle do Kubernetes

Você tem um cluster Kubernetes de três nós onde um nó do plano de controle perdeu seu disco. O membro etcd naquele nó desapareceu e kubectl get nodes agora trava porque o servidor de API não consegue atingir quórum nas gravações.

Aqui está o caminho de recuperação:

  1. Verifique os membros atuais a partir de um nó saudável: etcdctl member list. Você verá o membro com falha com uma URL vazia.
  2. Remova o membro morto: etcdctl member remove <MEMBER_ID>
  3. Provisione um novo nó com o mesmo hostname e IP (ou atualize o DNS).
  4. Adicione o substituto: etcdctl member add etcd-1-new --peer-urls=https://10.0.0.11:2380
  5. Inicie o etcd no novo nó com ETCD_INITIAL_CLUSTER_STATE=existing na configuração — não use new.
  6. Acompanhe a sincronização do novo membro: etcdctl endpoint status mostrará o número de revisão se aproximando em tempo real.

Todo o processo normalmente leva de cinco a dez minutos para um cluster com menos de 1 GB de dados etcd. Durante a remoção e antes que o novo membro atinja o quórum, o Kubernetes continua a servir leituras, mas bloqueia gravações.

Armadilhas e Casos Especiais

Nunca execute um número par de membros etcd. Um cluster de dois membros não tem tolerância a falhas — perder um membro imediatamente perde o quórum. Um cluster de quatro membros tolera apenas uma falha, igual a três membros, mas requer um nó extra. Mantenha 3 ou 5.

O I/O de disco é o principal gargalo do etcd. O etcd chama fdatasync a cada gravação. Se a latência do disco exceder consistentemente 10ms, você verá eleições de líderes e erros de request timeout no Kubernetes. Use armazenamento SSD ou NVMe. Verifique a latência do disco com: fio --rw=write --ioengine=sync --fdatasync=1 --directory=/var/lib/etcd --size=22m --bs=2300 --name=etcd-bench.

O etcd não é um banco de dados de propósito geral. A cota de armazenamento padrão é 2 GB. Clusters Kubernetes com muitos objetos ou uso intenso de recursos personalizados podem atingir esse limite. Monitore etcd_mvcc_db_total_size_in_bytes no Prometheus e compacte/desfragmente regularmente:

# Compactar revisões antigas (manter as últimas 1000)
rev=$(etcdctl endpoint status --write-out=json | jq '.[0].Status.header.revision')
etcdctl compact $((rev - 1000))
etcdctl defrag --cluster

O desvio de relógio causa eleições de líderes. O etcd usa o horário do relógio de parede para expiração de lease. Se os nós divergirem por mais de algumas centenas de milissegundos, você verá eleições de líderes espúrias. Execute NTP (chrony ou systemd-timesyncd) em todos os nós etcd e verifique com chronyc tracking.

A restauração de snapshot limpa a associação do cluster. Após a restauração, todos os membros são tratados como um novo cluster com a associação codificada no snapshot. Nunca restaure um snapshot em um cluster em execução sem parar todos os membros primeiro — você criará uma situação de split-brain.

Solução de Problemas

etcdserver: request timed out — Geralmente latência de disco. Verifique iostat -x 1 nos nós etcd. Verifique também a conectividade de peer: etcdctl endpoint health em cada nó individualmente.

etcdserver: mvcc: database space exceeded — A cota de armazenamento de 2 GB foi atingida. Execute compactação e desfragmentação conforme mostrado acima, ou aumente a cota com --quota-backend-bytes=4294967296 (4 GB) na configuração do etcd.

raft: failed to send message — Firewall bloqueando a porta 2380 entre peers, ou incompatibilidade de CN no certificado de peer. Verifique com openssl s_client -connect 10.0.0.12:2380 a partir de outro nó etcd.

certificate has expired — Os certificados de peer e cliente do etcd precisam de rotação antes de expirarem. Clusters Kubernetes gerenciados pelo kubeadm rotacionam automaticamente esses certificados em intervalos de 90 dias a 1 ano, mas clusters gerenciados manualmente não. Verifique a expiração: openssl x509 -in /etc/etcd/pki/etcd.pem -noout -dates.

etcd usando muita memória — O etcd armazena em cache o conjunto de trabalho na memória. Em clusters com muitos objetos, o RSS pode exceder 8 GB. Isso é normal. Defina --snapshot-count=5000 (padrão 100000) para acionar snapshots mais frequentes e reduzir o tamanho do log raft na memória.

Resumo

  • O etcd armazena todo o estado do cluster Kubernetes; é o serviço mais crítico no plano de controle
  • Sempre implante três ou cinco membros para produção — apenas números ímpares
  • Habilite TLS mútuo nas portas de cliente e peer; nunca exponha o etcd sem autenticação
  • Tire snapshots diários com etcdctl snapshot save e verifique-os com snapshot status
  • Restaure parando todos os membros, executando etcdutl snapshot restore em cada um com parâmetros de nó únicos, trocando o diretório de dados e reiniciando
  • Monitore a latência do disco (mantenha abaixo de 10ms), o tamanho do banco de dados (compacte ao se aproximar de 2 GB) e a estabilidade do líder
  • Use etcdctl member remove + member add para substituir um nó com falha sem uma restauração completa

Artigos Relacionados