AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

etcdctl —— 直连 K8s 元数据存储

一句话定义

etcdctl 是 etcd(K8s 的元数据存储)的命令行客户端。K8s 集群里所有"状态"——Node、Pod、Deployment、Secret、ConfigMap、Lease——全部存在 etcd 里。etcdctl 让你绕开 apiserver、直接看/改 etcd。

⚠️ 生产 etcd 不要 put / del。除非你完全清楚自己在干嘛,否则只用它做:snapshot 备份、health 检查、get 看键值(只读)。

典型场景

  • 升级 / 故障演练前:etcdctl snapshot save 备份
  • 控制面失联时:etcdctl endpoint health 看哪个 etcd 节点挂了
  • 排查"K8s 状态错乱":etcdctl get /registry/... 直接看 K8s 元数据
  • 集群恢复:etcdctl snapshot restore 从备份重建

etcdctl 的 v3 vs v2

export ETCDCTL_API=3                # **K8s 用的是 v3,永远设这个**

v2 已经废弃。每次跑 etcdctl 之前确认环境变量在:

echo $ETCDCTL_API     # 应该是 3

或者写到 .bashrc。


TLS 参数地狱

kubeadm 装的 etcd 默认开启 mTLS(双向证书认证)。每条 etcdctl 命令都要带 3 个证书:

etcdctl \
  --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 \
  endpoint health

强烈建议把这堆参数写成 shell function 或 alias:

# ~/.bashrc 或 /root/.bashrc
e() {
  ETCDCTL_API=3 etcdctl \
    --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 \
    "$@"
}

之后:

e endpoint health
e endpoint status -w table
e snapshot save /backup/etcd.db

或者用环境变量:

export ETCDCTL_API=3
export ETCDCTL_ENDPOINTS=https://127.0.0.1:2379
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/server.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/server.key

之后直接 etcdctl endpoint health。

怎么知道 endpoint 和证书路径

kubeadm 装的:

endpoints:  https://<节点 IP>:2379  (每个 cp 节点一个)
cacert:     /etc/kubernetes/pki/etcd/ca.crt
cert:       /etc/kubernetes/pki/etcd/server.crt    (或 healthcheck-client.crt)
key:        /etc/kubernetes/pki/etcd/server.key    (或 healthcheck-client.key)

确认:

ls /etc/kubernetes/pki/etcd/
# ca.crt  ca.key  healthcheck-client.crt  healthcheck-client.key  peer.crt  peer.key  server.crt  server.key

也可以看 etcd 静态 pod 配置:

grep -E "listen-client|trusted-ca|cert-file|key-file" /etc/kubernetes/manifests/etcd.yaml

健康检查(最常用 3 条)

endpoint health

etcdctl endpoint health
# https://127.0.0.1:2379 is healthy: successfully committed proposal: took = 5.012345ms

或者对所有 etcd 节点:

etcdctl \
  --endpoints=https://10.0.24.28:2379,https://10.0.24.29:2379,https://10.0.24.30:2379 \
  endpoint health -w table
# +--------------------------+--------+-------------+-------+
# | ENDPOINT                 | HEALTH | TOOK        | ERROR |
# +--------------------------+--------+-------------+-------+
# | https://10.0.24.28:2379  | true   | 5.012345ms  |       |
# | https://10.0.24.29:2379  | true   | 4.876543ms  |       |
# | https://10.0.24.30:2379  | true   | 5.234567ms  |       |
# +--------------------------+--------+-------------+-------+

endpoint status

etcdctl endpoint status -w table
# 看每个节点的: leader、raft term、raft index、db size

输出例子:

+-------+----+---------+---------+--------+-----------+-----------+
| ENDPT | ID | VERSION | DB SIZE | LEADER | RAFT TERM | RAFT INDEX|
+-------+----+---------+---------+--------+-----------+-----------+
| ...   | ...| 3.5.10  | 50 MB   | true   | 5         | 12345     |
| ...   | ...| 3.5.10  | 50 MB   | false  | 5         | 12345     |
| ...   | ...| 3.5.10  | 50 MB   | false  | 5         | 12345     |
+-------+----+---------+---------+--------+-----------+-----------+

健康集群所有节点 raft term / index 应该相同(或最多差一两个)。差太多说明某节点落后。

member list

etcdctl member list -w table
# +------------------+---------+--------+--------------------------+
# | ID               | STATUS  | NAME   | PEER ADDRS               |
# +------------------+---------+--------+--------------------------+
# | abc...           | started | m1     | https://10.0.24.28:2380  |
# | def...           | started | m2     | https://10.0.24.29:2380  |
# | ghi...           | started | m3     | https://10.0.24.30:2380  |
# +------------------+---------+--------+--------------------------+

排查"etcd 集群少了一个节点":member list 给你权威答案。


备份 / 恢复(面试 + CKA 必考)

备份 snapshot save

etcdctl snapshot save /backup/etcd-$(date +%F).db
# Snapshot saved at /backup/etcd-2026-05-27.db

# 验证
etcdctl --write-out=table snapshot status /backup/etcd-2026-05-27.db
# +----------+----------+------------+------------+
# | HASH     | REVISION | TOTAL KEYS | TOTAL SIZE |
# +----------+----------+------------+------------+
# | abcdef12 | 12345    | 5678       | 50 MB      |
# +----------+----------+------------+------------+

生产强烈建议每天 cron 自动备份:

cat > /etc/cron.d/etcd-backup <<'EOF'
0 2 * * * root /usr/local/bin/etcd-backup.sh
EOF

cat > /usr/local/bin/etcd-backup.sh <<'EOF'
#!/bin/bash
set -euo pipefail
DEST=/backup/etcd
mkdir -p "$DEST"
TS=$(date +%F-%H%M)

ETCDCTL_API=3 etcdctl snapshot save "$DEST/etcd-$TS.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

# 验证
ETCDCTL_API=3 etcdctl --write-out=table snapshot status "$DEST/etcd-$TS.db"

# 保留 14 天
find "$DEST" -name 'etcd-*.db' -mtime +14 -delete
EOF
chmod +x /usr/local/bin/etcd-backup.sh

恢复 snapshot restore

⚠️ 整个 K8s 控制面要停才能 restore。这是个核选项。

完整流程(CKA 演练):

# 1. 停 kubelet(避免它跟着重启 etcd)
systemctl stop kubelet

# 2. 停所有 etcd pod —— 把 manifest 挪走
mkdir -p /tmp/manifests-backup
mv /etc/kubernetes/manifests/etcd.yaml /tmp/manifests-backup/

# 3. 确认 etcd 容器已经停
crictl ps | grep etcd
# 应该没有

# 4. 备份当前 etcd 数据目录
mv /var/lib/etcd /var/lib/etcd.broken-$(date +%s)

# 5. 从 snapshot 还原
etcdctl snapshot restore /backup/etcd-2026-05-27.db \
  --data-dir=/var/lib/etcd \
  --name=m1 \                                              # ← 当前节点的 etcd member name
  --initial-cluster=m1=https://10.0.24.28:2380,m2=https://10.0.24.29:2380,m3=https://10.0.24.30:2380 \
  --initial-advertise-peer-urls=https://10.0.24.28:2380

# 6. 改 etcd 数据目录权限(kubeadm 默认 etcd 用户)
chown -R root:root /var/lib/etcd       # kubeadm 用 root,纯 etcd 用 etcd:etcd

# 7. 恢复 manifest
mv /tmp/manifests-backup/etcd.yaml /etc/kubernetes/manifests/

# 8. 启 kubelet
systemctl start kubelet
sleep 30

# 9. 验证
crictl ps | grep etcd                                       # etcd 应该 Running
etcdctl endpoint health                                      # healthy
kubectl get nodes                                            # 节点恢复

HA 集群(3 etcd 节点)restore 更麻烦:每个节点都要单独 restore、cluster ID 一致。Day12 演练。


看键值(只读)

K8s 把所有资源存在 /registry/... 前缀下:

etcdctl get / --prefix --keys-only | head
# /registry/apiregistration.k8s.io/apiservices/v1.
# /registry/apiregistration.k8s.io/apiservices/v1.apps
# /registry/clusterrolebindings/cluster-admin
# /registry/configmaps/default/kube-root-ca.crt
# /registry/deployments/default/nginx
# ...

# 看某个 pod 的元数据
etcdctl get /registry/pods/default/nginx-abc

# 输出是 protobuf 编码的,配 auger 解码
auger decode < <(etcdctl get /registry/pods/default/nginx-abc --print-value-only)

生产几乎不需要直接看 etcd——kubectl 已经够。这里是给"apiserver 挂了但想看状态"的极端情况。

数键值

etcdctl get / --prefix --keys-only | wc -l           # 总数
etcdctl get /registry/pods/ --prefix --keys-only | wc -l   # pod 数
etcdctl get /registry/secrets/ --prefix --keys-only | wc -l

K8s 集群里 secret / pod 数量异常大时(被插件污染),这种粗略统计能帮你找问题。


性能与维护

看 db 大小

etcdctl endpoint status -w table | awk -F'|' '{print $2, $5}'
# 看 DB SIZE 列

etcd db 默认上限 2GB(--quota-backend-bytes)。K8s 集群正常应该在 100-500MB。db 涨到 GB 级 = 出问题:

  • 死循环创建资源(Operator bug)
  • Secret 太多 / 太大
  • Event 没清理

Compaction(清理历史 revision)

etcdctl compact <revision>

K8s 1.5+ 默认 5 分钟自动 compaction。一般不用手动。

Defrag(碎片整理)

etcdctl defrag                              # 单节点
etcdctl defrag --cluster                    # 全集群(**会有几秒不可用**)

compaction 删了数据但没释放磁盘空间——要 defrag 才行。db 涨大、磁盘紧张时用。

生产 defrag 要轮转:一个节点一个节点做,避免同时不可用。


训练营常用速查

Day 1:刚装完看 etcd 健康

e endpoint health
e member list -w table

Day 2:练备份恢复

e snapshot save /tmp/backup.db
e snapshot status /tmp/backup.db
# 然后模拟故障 → restore

Day 12:灾难恢复演练

模拟某 etcd 节点磁盘损坏:

# 1. 停某 etcd 节点
ssh m2 'mv /etc/kubernetes/manifests/etcd.yaml /tmp/'
ssh m2 'rm -rf /var/lib/etcd'

# 2. cluster 应该还能读写(3 节点容忍 1 挂)
e endpoint health    # 在 m1 / m3 上跑应该 OK

# 3. 用 member remove 把它踢出 cluster
e member remove <m2-id>

# 4. 用 add 再把它加回
e member add m2 --peer-urls=https://10.0.24.29:2380

# 5. m2 用 --initial-cluster-state=existing 启动
# ... 复杂的,详见 Day12

常见踩坑

坑 1:error: context deadline exceeded

etcdctl endpoint health
# Error: context deadline exceeded

通常是:

  • endpoint URL 错 / 端口错(不是 2379 / 2380 混淆)
  • 证书错 / 不匹配
  • etcd 真挂了

诊断:

# 1. 端口能通吗
nc -zv 127.0.0.1 2379

# 2. cert 对吗
openssl s_client -connect 127.0.0.1:2379 -CAfile /etc/kubernetes/pki/etcd/ca.crt < /dev/null
# 看到 "Verify return code: 0 (ok)" 说明 cert 链对

# 3. etcd 进程还在吗
crictl ps | grep etcd
ps aux | grep etcd

坑 2:忘了 ETCDCTL_API=3

etcdctl endpoint health
# Error: unknown command "endpoint" for "etcdctl"

v2 没有 endpoint 子命令。export ETCDCTL_API=3。

坑 3:用 server.crt 不行,要用 healthcheck-client.crt

某些 kubeadm 版本里:

  • server.crt / server.key —— 是 etcd 服务端用的
  • healthcheck-client.crt / healthcheck-client.key —— 是给客户端用的

如果用 server cert 失败,换 healthcheck-client:

etcdctl \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
  endpoint health

坑 4:snapshot 不验证就放着

etcdctl snapshot save /backup/etcd.db
# 看着成功,没验证

# 半年后真灾难恢复,发现备份其实是空的 / 损坏的

备份完一定 snapshot status 验证,否则备份只是心理安慰。

坑 5:restore 用错 member name

etcdctl snapshot restore xxx.db --name=wrong-name --initial-cluster=m1=...,m2=...,m3=...
# 起来后 etcd cluster ID 不一致、永远 join 不进集群

--name 必须和 --initial-cluster 里的 hostname 对应。HA restore 时三个节点的 name / 顺序要完全对齐。

坑 6:直接 etcdctl del 删 K8s 数据

etcdctl del /registry/deployments/default/nginx
# kubectl 看不到 nginx 了,但是 controller 状态错乱

永远不要这样。K8s 状态是 apiserver 维护的、有 watcher / informer / cache。直接改 etcd 让所有 cache 失效、行为难预测。要删资源就 kubectl delete。

坑 7:HA 集群跨节点 endpoint 写错

etcdctl --endpoints=https://127.0.0.1:2379 endpoint health    # 只看本机
# OK,但其它节点呢?

etcdctl --endpoints=https://m1:2379,https://m2:2379,https://m3:2379 endpoint health
# 看全集群

HA 集群一定要列所有 endpoint,否则只能看到本机视角。


关联命令

  • kubeadm —— 装集群时建 etcd;备份是 upgrade 前必做
  • kubectl —— 正常运维用 kubectl,etcd 是底层逃生通道
  • crictl —— etcd 跑在静态 pod 里,看容器状态用 crictl
  • systemctl —— etcd 在 kubelet 下作为 static pod 管,不是 systemd unit
  • auger —— 解码 etcd 里的 protobuf K8s 资源
在 GitHub 上编辑此页