etcd 高可用分布式键值存储
etcd 高可用分布式键值存储
etcd 是 CoreOS 团队于 2013 年 6 月发起的开源项目,旨在构建一个高可用、强一致性的分布式键值数据库。etcd 使用 Go 语言开发,内部采用 Raft 一致性算法来保证数据一致性和可靠性。
- 官方网站: https://etcd.io
- GitHub 仓库: https://github.com/etcd-io/etcd
- 硬件推荐: https://etcd.io/docs/v3.4/op-guide/hardware/
为什么 Kubernetes 使用 etcd
Kubernetes(k8s)使用 etcd 作为其主要数据存储,用于管理整个集群的状态。etcd 保存了 Kubernetes 对象的配置数据、元数据和状态信息,例如 Pod、服务、部署和命名空间等。etcd 因其独特优势被 Kubernetes 选中:
etcd 的核心优势
- 完全复制:etcd 集群中的每个节点都保存完整的数据副本,确保无单点故障。
- 高可用性:etcd 能够容忍硬件故障和网络分区,适合分布式环境。
- 强一致性:通过 Raft 一致性算法,etcd 保证每次读取都能返回最新的写入数据。
- 简单 API:提供基于 gRPC 的清晰、用户友好的 API,易于集成。
- 安全性:支持自动化 TLS 和可选的客户端证书认证,确保通信安全。
- 高性能:基准测试显示每秒可处理 10,000 次写入,满足高吞吐需求。
- 可靠性:Raft 算法确保数据的可靠分布和容错能力。
etcd 在 Kubernetes 中的角色
在 Kubernetes 中,etcd 是集群状态的唯一真实数据源,存储以下内容:
- 配置数据(如 ConfigMap、Secret)。
- 资源元数据(如 Pod 规格、服务定义)。
- 集群状态(如节点状态、Pod 调度信息)。
由于 etcd 的关键作用,其性能和高可用性至关重要。etcd 数据存储在磁盘上,存储设备的 I/O 性能直接影响 Kubernetes 操作(如 Pod 调度和更新)的效率。为优化性能,推荐以下最佳实践:
- 使用固态硬盘(SSD):与传统 HDD 相比,SSD 可显著降低 I/O 延迟。
- 增加内存容量:更大的内存有助于缓存频繁访问的数据,减少磁盘 I/O。
- 定期备份:etcd 保存关键集群数据,必须定期备份以防止数据丢失。
与其他中间件的对比
etcd 是一种复制式集群解决方案,与 MySQL 集群、ZooKeeper 和 Redis 哨兵类似,数据在所有节点上完全复制。而 Redis Cluster、Kafka 和 Elasticsearch 则采用分片(数据分区)方式以实现扩展性。
# 复制式集群(全量数据复制)
- MySQL 集群
- ZooKeeper
- etcd
- Redis 哨兵# 分片式集群(数据分区)
- Redis Cluster
- Kafka
- Elasticsearch
etcd 配置
启动脚本参数详解
Kubernetes 集群中 etcd 节点的 systemd 服务配置文件如下:
# /etc/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/etcd-io/etcd[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/ # 数据存储目录
ExecStart=/usr/local/bin/etcd \ # etcd 二进制文件路径--name=etcd1 \ # 节点名称--cert-file=/etc/etcd/ssl/etcd.pem \ # 客户端证书--key-file=/etc/etcd/ssl/etcd-key.pem \ # 客户端私钥--peer-cert-file=/etc/etcd/ssl/etcd.pem \ # 集群节点间通信证书--peer-key-file=/etc/etcd/ssl/etcd-key.pem \ # 集群节点间通信私钥--trusted-ca-file=/etc/kubernetes/ssl/ca.pem \ # 客户端 CA 证书--peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \ # 集群节点 CA 证书--initial-advertise-peer-urls=https://192.168.7.101:2380 \ # 通告的集群通信端口--listen-peer-urls=https://192.168.7.101:2380 \ # 集群节点间监听端口--listen-client-urls=https://192.168.7.101:2379,http://127.0.0.1:2379 \ # 客户端访问地址--advertise-client-urls=https://192.168.7.101:2379 \ # 通告的客户端访问端口--initial-cluster-token=etcd-cluster-0 \ # 集群唯一标识 Token--initial-cluster=etcd1=https://192.168.7.101:2380,etcd2=https://192.168.7.102:2380,etcd3=https://192.168.7.103:2380 \ # 集群所有节点信息--initial-cluster-state=new \ # 集群状态(new 表示新建,existing 表示加入现有集群)--data-dir=/var/lib/etcd # 数据存储目录
Restart=on-failure
RestartSec=5
LimitNOFILE=65536[Install]
WantedBy=multi-user.target
- 节点名称(–name):唯一标识集群中的节点,建议与主机名一致。
- 证书和密钥:etcd 使用 TLS 保护客户端和节点间通信,需配置相关证书和 CA 文件。
- 端口说明:
- 2379:客户端访问 etcd 的默认端口(HTTP 或 HTTPS)。
- 2380:集群节点间通信的默认端口(用于 Raft 协议同步)。
- 集群 Token:确保同一集群中的节点使用相同的 Token。
- 数据目录:存储 etcd 数据和 WAL(Write-Ahead Log)文件,需确保磁盘空间充足。
验证 etcd 集群状态
以下命令用于检查 etcd 集群的健康状态和成员信息。所有命令需使用 ETCDCTL_API=3 以兼容 etcd v3 API。
检查节点心跳信息
验证每个节点的健康状态,确保集群正常运行。
export NODE_IPS="172.31.7.101 172.31.7.102 172.31.7.103"
for ip in ${NODE_IPS}; doETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://${ip}:2379 \--cacert=/etc/kubernetes/ssl/ca.pem \--cert=/etc/kubernetes/ssl/etcd.pem \--key=/etc/kubernetes/ssl/etcd-key.pem \endpoint health
done
显示集群成员信息
列出所有集群成员的详细信息,包括节点 ID 和状态。
ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table member list \--endpoints=https://172.31.7.101:2379 \--cacert=/etc/kubernetes/ssl/ca.pem \--cert=/etc/kubernetes/ssl/etcd.pem \--key=/etc/kubernetes/ssl/etcd-key.pem
查看节点详细状态
以表格形式显示每个节点的详细状态,包括延迟、版本和错误信息。
export NODE_IPS="172.31.7.101 172.31.7.102 172.31.7.103"
for ip in ${NODE_IPS}; doETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table endpoint status \--endpoints=https://${ip}:2379 \--cacert=/etc/kubernetes/ssl/ca.pem \--cert=/etc/kubernetes/ssl/etcd.pem \--key=/etc/kubernetes/ssl/etcd-key.pem
done
查看 etcd 数据
etcd 存储 Kubernetes 集群的各种数据,可以通过以下命令查看。
列出所有 Key
使用 --prefix 和 --keys-only 查看所有键路径。
# 查看所有 Key
ETCDCTL_API=3 etcdctl get / --prefix --keys-only# 过滤 Pod 相关信息
ETCDCTL_API=3 etcdctl get / --prefix --keys-only | grep pod# 过滤 Namespace 信息
ETCDCTL_API=3 etcdctl get / --prefix --keys-only | grep namespaces# 过滤 Deployment 信息
ETCDCTL_API=3 etcdctl get / --prefix --keys-only | grep deployment# 过滤 Calico 组件信息
ETCDCTL_API=3 etcdctl get / --prefix --keys-only | grep calico
查看指定 Key 的值
查询特定键的详细信息,例如 Calico 的 IPAM 数据。
ETCDCTL_API=3 etcdctl get /calico/ipam/v2/assignment/ipv4/block/10.20.241.64-26
# 示例输出
/calico/ipam/v2/assignment/ipv4/block/10.20.241.64-26
{"cidr": "10.20.241.64/26","affinity": "host:master01","allocations": [0, null, null, ...],"unallocated": [1, 2, 3, ...],"attributes": [{"handle_id": "ipip-tunnel-addr-master01","secondary": {"node": "master01", "type": "ipipTunnelAddress"}}],"deleted": false
}
查看所有 Calico 数据
列出所有以 /calico 开头的键。
ETCDCTL_API=3 etcdctl get /calico --keys-only --prefix | grep calico
etcd 数据操作(增删改查)
etcd 支持基本的 CRUD 操作,以下为示例:
# 添加数据
etcdctl put /name "xin"# 查询数据
etcdctl get /name
# 输出:
/name
xin# 更新数据(直接覆盖)
etcdctl put /name "xxx"
etcdctl get /name
# 输出:
/name
xxx# 删除数据
etcdctl del /name
# 输出:1(表示删除了 1 个键)# 删除 Pod 数据(需谨慎)
etcdctl del /registry/pods/default/net-test1
# 验证 Pod 是否被删除
kubectl get pods -A | grep net-test1
注意:直接操作 etcd 数据可能导致 Kubernetes 集群状态不一致,建议通过 Kubernetes API 管理资源,除非进行故障恢复或调试。
etcd Watch 机制
etcd v3 提供 Watch 机制,用于实时监控键的变化,支持监控单个键或键范围。当数据发生变化时,etcd 会主动通知客户端。
Watch 应用场景
- 实时监控配置变化(如 ConfigMap 更新)。
- 调试集群状态变化。
- 触发自动化操作(如 CI/CD 管道)。
示例:监控键变化
- 在 etcd 节点 1 上监控键
/data/name:
etcdctl watch /data/name
- 在 etcd 节点 2 上修改数据:
etcdctl put /data/name "xin123"
3.节点 1 的输出:
PUT
/data/name
xin123
etcd 数据备份与恢复
etcd 使用 WAL(Write-Ahead Log) 机制,所有数据修改在提交前都会先记录到 WAL 文件中。WAL 记录了数据变化的完整历程,是数据恢复的基础。
手动备份数据
使用 etcdctl snapshot save 命令备份 etcd 数据。
ETCDCTL_API=3 etcdctl snapshot save /data/etcd-backup-dir/etcd-xin-0105.db
# 示例输出
{"level":"info","ts":"2023-01-05T15:15:28.192+0800","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"etcd-xin-0105.db.part"}
...
Snapshot saved at /data/etcd-backup-dir/etcd-xin-0105.db
手动恢复数据
使用 etcdctl snapshot restore 恢复备份数据。
# 恢复到指定数据目录
ETCDCTL_API=3 etcdctl snapshot restore /data/etcd-backup-dir/etcd-xin-0105.db --data-dir=/tmp/etcd
自动化备份脚本
定期备份 etcd 数据的脚本:
#!/bin/bash
source /etc/profile
DATE=$(date +%Y-%m-%d_%H-%M-%S)
ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot save /data/etcd-backup-dir/etcd-snapshot-${DATE}.db# 定时任务(每 12 小时执行一次)
0 */12 * * * /bin/bash /root/etcd-backup.sh &> /dev/null
使用 kubeasz 备份与恢复
kubeasz 提供便捷的备份和恢复工具,但恢复期间 Kubernetes 控制平面服务(kube-apiserver、scheduler、controller-manager)将不可用。
# 备份
./ezctl backup k8s-01# 删除 Pod(测试数据恢复)
kubectl delete pod net-test1# 恢复
./ezctl restore k8s-01
etcd 数据恢复流程(集群故障)
当 etcd 集群宕机节点数超过集群总数的一半(如 3 节点集群宕机 2 台),整个集群将不可用。以下是恢复流程:
-
恢复服务器系统:确保所有节点硬件和操作系统正常。
-
重新部署 etcd 集群:安装 etcd 并配置新的集群。
-
停止 Kubernetes 服务
systemctl stop kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy -
停止 etcd 集群
systemctl stop etcd -
恢复备份数据:在每个 etcd 节点上使用相同的备份文件执行恢复:
ETCDCTL_API=3 etcdctl snapshot restore /data/etcd-backup-dir/etcd-snapshot.db --data-dir=/var/lib/etcd -
启动 etcd 集群:
systemctl start etcd, 验证集群状态:ETCDCTL_API=3 etcdctl endpoint health --endpoints=https://172.31.7.101:2379,... -
启动 Kubernetes 服务:
systemctl start kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy -
验证K8S集群状态:检查 Kubernetes 控制平面状态
kubectl get componentstatuses验证 Pod 数据:kubectl get pods -A
性能优化与运维建议
存储优化:
- 使用 NVMe SSD 或高性能 SAS 磁盘以降低 I/O 延迟。
- 确保数据目录(–data-dir)有足够的磁盘空间,避免 WAL 文件溢出。
内存分配:
- 分配至少 8GB 内存给 etcd 节点,缓存热点数据。
网络配置:
- 确保节点间网络延迟低于 10ms,带宽至少 1Gbps。
- 使用专用网络隔离 etcd 流量,避免与 Kubernetes 其他组件竞争。
监控与告警:
- 监控 etcd 的指标(如
etcd_server_leader_changes_seen_total、etcd_network_peer_round_trip_time_seconds)。 - 设置告警以检测节点故障、领导者选举频繁或磁盘 I/O 异常。
定期维护:
-
使用
etcdctl defrag整理数据库,减少碎片化。 -
定期清理历史修订版本,控制数据库大小:
ETCDCTL_API=3 etcdctl compact $(etcdctl get --from-key '' | wc -l)
原始文章:https://www.rzzz.net/cloudnative/k8s/etcd.html
