etcd | Banco de Dados
- etcd | Banco de Dados
O etcd é um banco de dados key-value distribuído, fortemente consistente, usado para armazenar dados críticos de sistemas distribuídos. Ele é muito conhecido por ser o storage do Kubernetes, mas também pode ser usado para service discovery, coordenação distribuída, feature flags, locks distribuídos, configuração dinâmica e controle de estado de clusters. A própria documentação define o etcd como um key-value store distribuído, confiável e fortemente consistente para dados críticos de sistemas distribuídos. (etcd)
Quando usar etcd
Use etcd quando você precisa de:
| Cenário | Faz sentido? | Observação |
|---|---|---|
| Configuração distribuída | Sim | Exemplo: /config/api/rate-limit = 1000 |
| Service discovery | Sim | Serviços registram presença com TTL |
| Leader election | Sim | Um nó assume liderança por lease/lock |
| Locks distribuídos | Sim | Útil para evitar execução concorrente |
| Estado de cluster | Sim | Exemplo: membros, workers, partições |
| Feature flags simples | Sim | Se precisar de consistência forte |
| Cache de alta volumetria | Não | Use Redis |
| Banco transacional de negócio | Não | Use PostgreSQL, MySQL, MongoDB etc. |
| Fila/mensageria | Não | Use RabbitMQ, Kafka, NATS etc. |
| Eventos de grande volume | Não | etcd não é event store |
Regra prática:
etcd é para metadados críticos e coordenação, não para dados de negócio volumosos.
Conceitos principais
Key-value store
O modelo é simples:
chave -> valor
Exemplo:
/config/app/theme -> dark
/services/api-01/status -> healthy
/locks/job-conciliacao -> node-01
As chaves normalmente seguem uma estrutura parecida com diretórios:
/config/api/database/url
/config/api/database/max-connections
/services/payment-api/instance-01
/services/payment-api/instance-02
Isso facilita busca por prefixo.
Consistência forte
O etcd usa o algoritmo Raft para consenso distribuído. Isso significa que o cluster precisa concordar sobre as alterações antes de considerar uma escrita como confirmada.
Em termos práticos:
- existe um leader
- os outros nós são followers
- escritas passam pelo leader
- o cluster precisa de quorum
- se perder quorum, o cluster não consegue aceitar escrita
O etcd foi projetado para lidar com eleição de leader e falhas de máquina, inclusive falha do nó líder. (etcd)
Quorum no etcd
O quorum é a maioria dos membros do cluster.
| Quantidade de membros | Quorum | Pode perder quantos nós? |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 5 | 3 | 2 |
| 7 | 4 | 3 |
Por isso, em produção, normalmente se usa 3 ou 5 membros.
Evite cluster com 2 membros. Se um cair, sobra apenas 1, e 1 de 2 não forma maioria.
Instalação com Docker
Para ambiente local:
docker run -d \
--name etcd-node-1 \
-p 2379:2379 \
-p 2380:2380 \
-v etcd-data:/etcd-data \
quay.io/coreos/etcd:v3.6.0 \
etcd \
--name=etcd-node-1 \
--data-dir=/etcd-data \
--listen-client-urls=http://0.0.0.0:2379 \
--advertise-client-urls=http://localhost:2379 \
--listen-peer-urls=http://0.0.0.0:2380 \
--initial-advertise-peer-urls=http://etcd-node-1:2380 \
--initial-cluster=etcd-node-1=http://etcd-node-1:2380 \
--initial-cluster-token=etcd-cluster-1 \
--initial-cluster-state=new
Testando:
docker exec -it etcd etcdctl endpoint health
ou no terminal próprio
etcdctl --endpoints=http://localhost:2379 endpoint health
Saída esperada:
127.0.0.1:2379 is healthy
Portas principais
| Porta | Uso |
|---|---|
2379 | Comunicação dos clients |
2380 | Comunicação entre membros do cluster |
A porta 2379 é usada por aplicações, etcdctl e clients.
A porta 2380 é usada internamente entre os nós do cluster.
Instalação local do etcdctl
O etcdctl é a CLI oficial para interagir com o etcd.
Verifique a versão:
etcdctl version
Para usar a API v3:
export ETCDCTL_API=3
Nas versões modernas, a API v3 é o padrão prático. A documentação atual destaca que a API v2 foi depreciada no etcd v3.5, enquanto a API v3 é baseada em gRPC. (etcd)
Comandos básicos com etcdctl
Inserir uma chave
etcdctl put /config/app/name "minha-api"
Buscar uma chave
etcdctl get /config/app/name
Saída:
/config/app/name
minha-api
Buscar apenas o valor
etcdctl get /config/app/name --print-value-only
Deletar uma chave
etcdctl del /config/app/name
Buscar por prefixo
etcdctl get /config/ --prefix
Exemplo:
etcdctl put /config/api/port "8080"
etcdctl put /config/api/env "production"
etcdctl put /config/api/database "postgres"
etcdctl get /config/api/ --prefix
Saída:
/config/api/database
postgres
/config/api/env
production
/config/api/port
8080
Organização de chaves
Um padrão comum é separar por domínio:
/config/<app>/<chave>
/services/<service>/<instance>
/locks/<resource>
/features/<feature-name>
/tenants/<tenant-id>/<config>
Exemplo:
etcdctl put /config/payment-api/database/host "postgres.internal"
etcdctl put /config/payment-api/database/port "5432"
etcdctl put /config/payment-api/cache/ttl "300"
Watch
O watch permite observar alterações em uma chave ou prefixo.
Observar uma chave
Terminal 1:
etcdctl watch /config/api/env
Terminal 2:
etcdctl put /config/api/env "production"
O Terminal 1 recebe o evento.
Observar por prefixo
etcdctl watch /config/api/ --prefix
Isso é útil para:
- recarregar configuração em runtime
- detectar mudança de feature flag
- atualizar estado de serviços
- reagir à entrada/saída de instâncias
A API v3 do etcd possui suporte a watch, lease, transactions e operações key-value, com modelo MVCC para histórico de revisões. (etcd)
Revisions
Cada alteração no etcd gera uma revision.
Exemplo:
etcdctl put /config/app/version "1"
etcdctl put /config/app/version "2"
etcdctl put /config/app/version "3"
Buscar metadados:
etcdctl get /config/app/version -w json
Exemplo de campos importantes:
{
"header": {
"revision": 10
},
"kvs": [
{
"key": "L2NvbmZpZy9hcHAvdmVyc2lvbg==",
"value": "Mw==",
"create_revision": 8,
"mod_revision": 10,
"version": 3
}
]
}
| Campo | Significado |
|---|---|
revision | revision global do cluster |
create_revision | revision em que a chave foi criada |
mod_revision | última revision em que a chave foi alterada |
version | quantidade de alterações na chave |
O etcd usa MVCC, permitindo visualizar versões anteriores enquanto o histórico ainda não foi compactado. (etcd)
Buscar uma revision antiga
etcdctl get /config/app/version --rev=8
Isso só funciona se a revision ainda não foi compactada.
Compactação
O etcd mantém histórico de alterações por um tempo. Para evitar crescimento infinito, é necessário compactar revisions antigas.
Exemplo:
etcdctl compact 1000
Depois disso, revisions anteriores a 1000 não ficam mais disponíveis.
Defrag
Compactar remove histórico lógico, mas pode não reduzir imediatamente o tamanho físico do banco. Para recuperar espaço em disco, use defrag.
etcdctl defrag
Em cluster:
etcdctl --endpoints=http://node1:2379 defrag
etcdctl --endpoints=http://node2:2379 defrag
etcdctl --endpoints=http://node3:2379 defrag
Leases
Lease é um TTL associado a uma ou mais chaves.
Quando o lease expira, as chaves associadas são removidas automaticamente.
Criar lease
etcdctl lease grant 30
Saída:
lease 694d... granted with TTL(30s)
Associar chave ao lease
etcdctl put /services/api/instance-01 "10.0.0.10:8080" --lease=694d...
Ver lease
etcdctl lease timetolive 694d...
Manter lease vivo
etcdctl lease keep-alive 694d...
Revogar lease
etcdctl lease revoke 694d...
Uso comum:
/services/payment-api/instance-01 -> 10.0.0.10:8080
/services/payment-api/instance-02 -> 10.0.0.11:8080
Cada instância registra sua presença com lease. Se a aplicação morrer e parar de renovar o lease, a chave desaparece.
Service discovery com etcd
Exemplo registrando uma instância:
LEASE_ID=$(etcdctl lease grant 30 | awk '{print $2}')
etcdctl put /services/catalog-api/instance-01 "http://10.0.0.10:8080" --lease=$LEASE_ID
etcdctl lease keep-alive $LEASE_ID
Consumidor buscando instâncias:
etcdctl get /services/catalog-api/ --prefix
Aplicação pode manter um watch no prefixo:
etcdctl watch /services/catalog-api/ --prefix
Assim, quando uma instância entra ou sai, os consumidores são notificados.
Locks distribuídos
O etcd pode ser usado para evitar que dois processos executem a mesma tarefa crítica ao mesmo tempo.
Exemplo:
etcdctl lock /locks/job-conciliacao
Enquanto esse comando estiver ativo, outro processo tentando adquirir o mesmo lock ficará bloqueado.
Uso típico:
Somente um worker pode executar o job X por vez.
Exemplos:
- conciliação financeira
- processamento de lote
- migração de dados
- eleição de leader
- execução de scheduler distribuído
Transactions
Transactions permitem executar operações condicionais.
Exemplo conceitual:
SE /config/app/version ainda for revision X
ENTÃO atualize para Y
SENÃO falhe
Isso é útil para controle de concorrência otimista.
Exemplo com etcdctl txn:
etcdctl txn
Fluxo interativo:
compares:
value("/config/app/env") = "dev"
success requests:
put /config/app/env prod
failure requests:
get /config/app/env
Transactions são importantes para:
- compare-and-swap
- locks
- leader election
- atualização segura de configuração
- evitar sobrescrita concorrente
A API do etcd organiza operações em grupos como key-value, watch e lease; também oferece transações na API v3. (etcd)
Cluster etcd com 3 nós
Exemplo de topologia:
| Nó | Client URL | Peer URL |
|---|---|---|
etcd-1 | http://10.0.0.1:2379 | http://10.0.0.1:2380 |
etcd-2 | http://10.0.0.2:2379 | http://10.0.0.2:2380 |
etcd-3 | http://10.0.0.3:2379 | http://10.0.0.3:2380 |
etcd-1
etcd \
--name etcd-1 \
--data-dir /var/lib/etcd \
--listen-client-urls http://10.0.0.1:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://10.0.0.1:2379 \
--listen-peer-urls http://10.0.0.1:2380 \
--initial-advertise-peer-urls http://10.0.0.1:2380 \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380 \
--initial-cluster-token cluster-prod-01 \
--initial-cluster-state new
etcd-2
etcd \
--name etcd-2 \
--data-dir /var/lib/etcd \
--listen-client-urls http://10.0.0.2:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://10.0.0.2:2379 \
--listen-peer-urls http://10.0.0.2:2380 \
--initial-advertise-peer-urls http://10.0.0.2:2380 \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380 \
--initial-cluster-token cluster-prod-01 \
--initial-cluster-state new
etcd-3
etcd \
--name etcd-3 \
--data-dir /var/lib/etcd \
--listen-client-urls http://10.0.0.3:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://10.0.0.3:2379 \
--listen-peer-urls http://10.0.0.3:2380 \
--initial-advertise-peer-urls http://10.0.0.3:2380 \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380 \
--initial-cluster-token cluster-prod-01 \
--initial-cluster-state new
Verificar saúde do cluster
etcdctl \
--endpoints=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379 \
endpoint health
Ver status dos endpoints
etcdctl \
--endpoints=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379 \
endpoint status --write-out=table
Saída típica:
+-----------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://10.0.0.1:2379 | abc... | 3.6.0 | 20 MB | true | false | 8 | 12345 | 12345 | |
| http://10.0.0.2:2379 | def... | 3.6.0 | 20 MB | false | false | 8 | 12345 | 12345 | |
| http://10.0.0.3:2379 | ghi... | 3.6.0 | 20 MB | false | false | 8 | 12345 | 12345 | |
+-----------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
Campos importantes:
| Campo | O que olhar |
|---|---|
IS LEADER | Qual nó é o líder |
RAFT TERM | Termo atual do Raft |
RAFT INDEX | Índice replicado |
RAFT APPLIED INDEX | Índice aplicado |
DB SIZE | Tamanho do banco |
ERRORS | Problemas no endpoint |
Adicionar membro ao cluster
No cluster existente:
etcdctl member add etcd-4 --peer-urls=http://10.0.0.4:2380
O comando retorna uma configuração que deve ser usada para iniciar o novo membro.
Exemplo para o novo nó:
etcd \
--name etcd-4 \
--data-dir /var/lib/etcd \
--listen-client-urls http://10.0.0.4:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://10.0.0.4:2379 \
--listen-peer-urls http://10.0.0.4:2380 \
--initial-advertise-peer-urls http://10.0.0.4:2380 \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380,etcd-4=http://10.0.0.4:2380 \
--initial-cluster-state existing
Remover membro
Listar membros:
etcdctl member list
Remover:
etcdctl member remove <member-id>
Backup
Backup no etcd é feito com snapshot.
etcdctl \
--endpoints=http://127.0.0.1:2379 \
snapshot save snapshot.db
Verificar snapshot:
etcdutl snapshot status snapshot.db --write-out=table
A documentação de disaster recovery do etcd informa que uma única snapshot db é suficiente para restaurar um cluster, e que todos os membros devem restaurar usando a mesma snapshot. (etcd)
Restore
Exemplo restaurando snapshot para 3 membros.
Restaurar etcd-1
etcdutl snapshot restore snapshot.db \
--name etcd-1 \
--data-dir /var/lib/etcd-restored \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380 \
--initial-advertise-peer-urls http://10.0.0.1:2380
Restaurar etcd-2
etcdutl snapshot restore snapshot.db \
--name etcd-2 \
--data-dir /var/lib/etcd-restored \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380 \
--initial-advertise-peer-urls http://10.0.0.2:2380
Restaurar etcd-3
etcdutl snapshot restore snapshot.db \
--name etcd-3 \
--data-dir /var/lib/etcd-restored \
--initial-cluster etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380 \
--initial-advertise-peer-urls http://10.0.0.3:2380
Depois, subir cada membro apontando para o novo data-dir.
A restauração sobrescreve metadados como member ID e cluster ID, evitando que o membro restaurado tente entrar acidentalmente no cluster antigo. (etcd)
Segurança
Em produção, não use etcd aberto sem autenticação e sem TLS.
Checklist mínimo:
- habilitar TLS para client
- habilitar TLS para peer
- habilitar autenticação
- criar usuários e roles
- limitar acesso às portas
2379e2380 - não expor etcd publicamente na internet
- fazer backup recorrente
- monitorar saúde do cluster
Autenticação
Criar usuário root
etcdctl user add root
Criar role root
etcdctl role add root
Dar permissão root
etcdctl user grant-role root root
Habilitar autenticação
etcdctl auth enable
Depois disso, chamadas precisam de usuário e senha:
etcdctl \
--user=root:minha-senha \
get /config/api/env
Roles e permissões
Criar role:
etcdctl role add app-config-reader
Permitir leitura em um prefixo:
etcdctl role grant-permission app-config-reader read /config/api/ --prefix
Criar usuário:
etcdctl user add minha-api
Associar role:
etcdctl user grant-role minha-api app-config-reader
Usar:
etcdctl \
--user=minha-api:senha \
get /config/api/ --prefix
TLS para clients
Exemplo de chamada com certificados:
etcdctl \
--endpoints=https://10.0.0.1:2379 \
--cacert=/etc/etcd/pki/ca.crt \
--cert=/etc/etcd/pki/client.crt \
--key=/etc/etcd/pki/client.key \
endpoint health
Configuração do servidor:
etcd \
--name etcd-1 \
--data-dir /var/lib/etcd \
--listen-client-urls https://10.0.0.1:2379 \
--advertise-client-urls https://10.0.0.1:2379 \
--client-cert-auth \
--trusted-ca-file /etc/etcd/pki/ca.crt \
--cert-file /etc/etcd/pki/server.crt \
--key-file /etc/etcd/pki/server.key
TLS entre peers
Para cluster em produção, também proteja a comunicação entre os membros:
etcd \
--name etcd-1 \
--listen-peer-urls https://10.0.0.1:2380 \
--initial-advertise-peer-urls https://10.0.0.1:2380 \
--peer-client-cert-auth \
--peer-trusted-ca-file /etc/etcd/pki/ca.crt \
--peer-cert-file /etc/etcd/pki/peer.crt \
--peer-key-file /etc/etcd/pki/peer.key
Exemplo com Docker Compose local
services:
etcd:
image: quay.io/coreos/etcd:v3.6.0
container_name: etcd-node-1
ports:
- "2379:2379"
- "2380:2380"
volumes:
- etcd-data:/etcd-data
command:
- etcd
- --name=etcd-node-1
- --data-dir=/etcd-data
- --listen-client-urls=http://0.0.0.0:2379
- --advertise-client-urls=http://localhost:2379
- --listen-peer-urls=http://0.0.0.0:2380
- --initial-advertise-peer-urls=http://etcd-node-1:2380
- --initial-cluster=etcd-node-1=http://etcd-node-1:2380
- --initial-cluster-token=etcd-cluster-1
- --initial-cluster-state=new
volumes:
etcd-data:
Subir:
docker compose up -d
Testar:
docker exec -it etcd etcdctl endpoint health
Exemplo usando etcd em aplicação .NET
Pacote comum:
dotnet add package dotnet-etcd
Exemplo básico:
using dotnet_etcd;
var client = new EtcdClient("http://localhost:2379");
await client.PutAsync("/config/minha-api/database", "postgres");
var result = await client.GetValAsync("/config/minha-api/database");
Console.WriteLine(result);
Buscar configurações por prefixo em .NET
using dotnet_etcd;
using Etcdserverpb;
using Mvccpb;
var client = new EtcdClient("http://localhost:2379");
var response = await client.GetRangeAsync("/config/minha-api/");
foreach (var kv in response.Kvs)
{
var key = kv.Key.ToStringUtf8();
var value = kv.Value.ToStringUtf8();
Console.WriteLine($"{key} = {value}");
}
Usar etcd para feature flag
Gravar flag:
etcdctl put /features/new-checkout/enabled "true"
Ler na aplicação:
var enabled = await client.GetValAsync("/features/new-checkout/enabled");
if (enabled == "true")
{
Console.WriteLine("Novo checkout habilitado");
}
else
{
Console.WriteLine("Novo checkout desabilitado");
}
Usar watch em .NET
Exemplo conceitual:
using dotnet_etcd;
var client = new EtcdClient("http://localhost:2379");
client.Watch("/features/new-checkout/enabled", watchEvent =>
{
foreach (var evt in watchEvent.Events)
{
var key = evt.Kv.Key.ToStringUtf8();
var value = evt.Kv.Value.ToStringUtf8();
Console.WriteLine($"Alteração detectada: {key} = {value}");
}
});
Uso prático:
Quando a flag muda no etcd, a aplicação atualiza o comportamento sem restart.
Padrão: configuração dinâmica
Estrutura:
/config/catalog-api/database/host
/config/catalog-api/database/port
/config/catalog-api/redis/host
/config/catalog-api/cache/default-ttl
/config/catalog-api/features/novo-fluxo
Aplicação:
- carrega configurações no startup
- mantém
watchno prefixo/config/catalog-api/ - atualiza configuração em memória quando houver mudança
- usa fallback se etcd ficar indisponível
Ponto importante:
Não faça a aplicação depender de chamada ao etcd em toda requisição HTTP. Carregue em memória e atualize por watch.
Padrão: service discovery
Cada serviço registra a própria instância:
/services/payment-api/instance-01 -> http://10.0.0.10:8080
/services/payment-api/instance-02 -> http://10.0.0.11:8080
Com lease:
LEASE_ID=$(etcdctl lease grant 30 | awk '{print $2}')
etcdctl put /services/payment-api/instance-01 "http://10.0.0.10:8080" --lease=$LEASE_ID
etcdctl lease keep-alive $LEASE_ID
Consumers buscam:
etcdctl get /services/payment-api/ --prefix
Padrão: leader election
Ideia:
Vários nós tentam criar/adquirir uma chave de liderança.
Quem conseguir, vira leader.
Se o lease expirar, outro nó assume.
Estrutura:
/election/job-conciliacao/leader -> worker-03
Uso:
- scheduler distribuído
- processamento singleton
- jobs críticos
- orquestração de workers
Padrão: lock distribuído
Exemplo:
etcdctl lock /locks/fechamento-caixa
Enquanto o lock estiver ativo, outro processo não entra na seção crítica.
Uso típico:
Apenas um processo pode fazer fechamento de caixa por vez.
Observabilidade
Ver saúde:
etcdctl endpoint health
Ver status:
etcdctl endpoint status --write-out=table
Ver alarmes:
etcdctl alarm list
Ver membros:
etcdctl member list
Métricas Prometheus
O etcd expõe métricas HTTP normalmente no endpoint:
/metrics
Exemplo:
curl http://localhost:2379/metrics
Métricas importantes:
| Métrica | O que indica |
|---|---|
etcd_server_has_leader | Se o nó enxerga leader |
etcd_server_leader_changes_seen_total | Trocas de leader |
etcd_disk_wal_fsync_duration_seconds | Latência de escrita no WAL |
etcd_disk_backend_commit_duration_seconds | Latência de commit no backend |
etcd_mvcc_db_total_size_in_bytes | Tamanho total do banco |
etcd_network_peer_round_trip_time_seconds | Latência entre peers |
grpc_server_handled_total | Requisições gRPC processadas |
Alertas úteis:
etcd_server_has_leader == 0
rate(etcd_server_leader_changes_seen_total[5m]) > 0
etcd_mvcc_db_total_size_in_bytes crescendo muito rápido
Manutenção
Rotina recomendada:
| Tarefa | Frequência |
|---|---|
| Snapshot backup | recorrente |
| Teste de restore | recorrente |
| Compactação | conforme volume |
| Defrag | quando DB físico crescer |
| Monitorar leader changes | contínuo |
| Monitorar latência de disco | contínuo |
| Monitorar quorum | contínuo |
O próprio guia de upgrade do etcd recomenda criar e baixar snapshot antes de upgrade, para permitir restauração em caso de problema. (etcd)
Boas práticas
Use número ímpar de membros
Prefira:
3 ou 5 membros
Evite:
2 membros
Use disco rápido
etcd é sensível a latência de disco porque depende de WAL e persistência.
Evite:
- disco lento
- disco compartilhado ruim
- storage de rede instável
- alta contenção de I/O
Não grave payload grande
Ruim:
/config/blob-gigante -> JSON de 10 MB
Melhor:
/config/blob-ref -> s3://bucket/config.json
Armazene no etcd apenas metadados ou referências.
Não use como cache
Para cache:
Redis
Para coordenação:
etcd
Não exponha publicamente
Bloqueie:
0.0.0.0:2379 na internet
0.0.0.0:2380 na internet
Permita apenas:
aplicações internas
membros do cluster
rede privada
Tenha backup testado
Backup sem restore testado é só uma esperança.
Tenha:
- snapshot automatizado
- retenção
- cópia externa
- teste periódico de restore
- runbook documentado
Erros comuns
Usar cluster com 2 nós
Problema:
Se um nó cair, o cluster perde quorum.
Use 3 membros.
Usar etcd como banco de negócio
Errado:
/orders/123
/customers/456
/invoices/789
Use banco relacional/documento para isso.
Fazer leitura no etcd a cada request
Errado:
Request HTTP -> busca config no etcd -> responde
Melhor:
Startup -> carrega config
Watch -> atualiza cache local
Request HTTP -> usa config em memória
Não configurar compactação
Problema:
Histórico cresce indefinidamente.
Configure rotina de compactação.
Não monitorar leader changes
Trocas frequentes de leader indicam problema:
- rede instável
- disco lento
- CPU saturada
- timeout mal configurado
- nó com pausa de GC ou contenção
Comandos úteis
Inserir
etcdctl put /foo "bar"
Ler
etcdctl get /foo
Ler por prefixo
etcdctl get /foo --prefix
Deletar
etcdctl del /foo
Deletar por prefixo
etcdctl del /foo --prefix
Watch
etcdctl watch /foo
Watch por prefixo
etcdctl watch /foo --prefix
Criar lease
etcdctl lease grant 60
Listar lease
etcdctl lease list
Ver TTL
etcdctl lease timetolive <lease-id>
Renovar lease
etcdctl lease keep-alive <lease-id>
Revogar lease
etcdctl lease revoke <lease-id>
Lock
etcdctl lock /locks/minha-tarefa
Snapshot
etcdctl snapshot save snapshot.db
Status do snapshot
etcdutl snapshot status snapshot.db --write-out=table
Health
etcdctl endpoint health
Status
etcdctl endpoint status --write-out=table
Membros
etcdctl member list
Exemplo de runbook básico
Verificar se o cluster está saudável
etcdctl \
--endpoints=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379 \
endpoint health
Ver quem é o leader
etcdctl \
--endpoints=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379 \
endpoint status --write-out=table
Fazer backup manual
etcdctl \
--endpoints=http://10.0.0.1:2379 \
snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db
Verificar backup
etcdutl snapshot status /backup/etcd-20260522-120000.db --write-out=table
Compactar
REVISION=$(etcdctl endpoint status --write-out=json | jq '.[0].Status.header.revision')
etcdctl compact $REVISION
Defrag
etcdctl defrag
Checklist de produção
| Item | Obrigatório? |
|---|---|
| Cluster com 3 ou 5 membros | Sim |
| TLS client | Sim |
| TLS peer | Sim |
| Autenticação | Sim |
| Backup automatizado | Sim |
| Restore testado | Sim |
| Métricas Prometheus | Sim |
| Alertas de leader/quorum | Sim |
| Disco rápido | Sim |
| Rede privada entre peers | Sim |
Firewall nas portas 2379 e 2380 | Sim |
| Compactação/defrag planejados | Sim |
| Não armazenar payload gigante | Sim |
| Não usar como banco transacional | Sim |
Resumo mental
| Pergunta | Resposta |
|---|---|
| etcd é banco de dados? | Sim, key-value distribuído |
| É para dados de negócio? | Não é o ideal |
| É para coordenação? | Sim |
| Tem consistência forte? | Sim |
| Usa Raft? | Sim |
| Precisa de quorum? | Sim |
| Pode usar com Kubernetes? | Sim, Kubernetes usa etcd como storage do estado do cluster |
| Serve para service discovery? | Sim |
| Serve para lock distribuído? | Sim |
| Serve como Redis? | Não |
| Serve como fila? | Não |
| Precisa de backup? | Sim |
| Precisa de TLS em produção? | Sim |
| Cluster com 2 nós é bom? | Não |