etcd
环境信息
- etcd v3.5
wget https://github.com/etcd-io/etcd/releases/download/v3.5.9/etcd-v3.5.9-linux-amd64.tar.gz |
启动 etcd
etcd |
常用管理命令
etcd
查看版本信息
etcd --version |
创建集群
etcd
创建集群涉及参数说明
name | 说明 | 命令行参数 |
---|---|---|
name |
每个集群成员的唯一名称 | --name=etcd0 |
initial-advertise-peer-urls |
群成员广播给集群其他成员(用于连接本节点)的 URL 默认为 http://IP:2380 |
--initial-advertise-peer-urls=http://10.0.0.10:2380 |
listen-peer-urls |
在这些(一个或多个) URL 上监听其他集群成员的连接请求 通信包括了集群管理任务、数据同步和心跳检测等 |
http://10.0.0.10:2380,http://127.0.0.1:2380 |
listen-client-urls |
该成员监听客户端连接的 URL。 默认端口 2379 | --listen-client-urls=http://10.0.0.10:2379,http://127.0.0.1:2379 |
advertise-client-urls |
该成员广播给客户端的 URL | --advertise-client-urls=http://10.0.0.10:2379 |
initial-cluster |
所有 etcd 成员的初始列表 |
--initial-cluster=etcd0=http://10.0.0.10:2380,etcd1=http://10.0.0.11:2380,etcd2=http://10.0.0.12:2380 |
data-dir |
etcd 数据的存储目录。 |
--data-dir=/var/lib/etcd |
initial-cluster-token |
初始集群的唯一标识符,用于区分不同的 etcd 集群 |
--initial-cluster-token=my-etcd-token |
initial-cluster-state |
初始集群状态,可以是 new 或 existing 。通常在引导新集群时使用 new ,而在添加或删除成员时使用 existing 。 |
--initial-cluster-state=new |
quota-backend-bytes |
etcd 的后端数据库大小的硬限制,默认是 2GB |
--quota-backend-bytes=3000000000 |
cert-file key-file |
用于 HTTPS 的证书和私钥 | --cert-file=/etc/kubernetes/pki/etcd/server.crt --key-file=/etc/kubernetes/pki/etcd/server.key |
trusted-ca-file |
客户端和对等体的验证所需的 CA 证书 | --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt |
client-cert-auth |
启用客户端证书验证,默认为 false |
--client-cert-auth |
listen-peer-urls
和 initial-advertise-peer-urls
的区别说明:
listen-peer-urls
这个参数指定了
etcd
成员应该在哪些地址和端口上监听来自其他etcd
成员的请求(数据同步、领导选举、集群更改等相关)主要用途是定义哪个网络接口和端口号应该被
etcd
服务绑定,以便它可以接收来自其他成员的连接initial-advertise-peer-urls
这个参数告诉
etcd
该如何 通告自己 给集群中的其他成员。这是其他集群成员用来联系此etcd
成员的地址。主要用途是 当新成员加入集群时,它需要通知其他成员自己的存在,以及如何与自己通信,因此它必须是个其他节点可达的 Endpoints,如
http://0.0.0.0:2380
就不行。listen-client-urls
和advertise-client-urls
的区别同理
示例环境说明
主机 | IP | 角色 |
---|---|---|
etcd1 | 172.17.0.2/16 | etcd node |
etcd2 | 172.17.0.3/16 | etcd node |
etcd3 | 172.17.0.4/16 | etcd node |
分别在 3 个节点上执行以下 3 条命令,创建集群
etcd1
执行命令:
etcd --data-dir=data.etcd --name etcd1 \ |
etcd2
执行命令:
etcd --data-dir=data.etcd --name etcd2 \ |
etcd3
执行命令:
etcd --data-dir=data.etcd --name etcd3 \ |
检查节点健康状态
ENDPOINT=http://172.17.0.3:2380,http://172.17.0.2:2380,http://172.17.0.4:2380 |
etcdctl
查看版本信息
etcdctl version |
etcd 集群管理
查看 etcd 集群成员列表
Kubernetes 中查看 etcd
集群成员列表使用如下命令
kubectl exec -n kube-system -it etcd-k8s-master1 -- sh -c "ETCDCTL_API=3 etcdctl member list --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" |
指定输出格式为 table
etcdctl member list --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key --write-out=table |
输出内容说明如下:
3c087bf12db7a0f
: 集群中每一个成员的唯一 ID。started
: 集群成员的当前状态。started
表示活动的。k8s-master2
:etcd
集群成员的名字,通常与其主机名或节点名相对应https://172.31.30.115:2380
:Peer URLs
,其他etcd
成员用于与该成员通信的 URL。默认为 本地 IP 的 2380 端口https://172.31.30.123:2379
:Client URLs
,客户端用于与etcd
成员通信的 URL。默认为 本地 IP 的 2379 端口Is Learner
: 表示该成员是否是一个learner
。Learner 是etcd
的一个新功能,允许一个成员作为非投票成员加入集群,直到它准备好成为一个完全参与的成员。false
表示它们都不是learners
检查集群状态
检查单个节点的集群配置状态
etcdctl --write-out=table endpoint status --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key |
查看所有节点的集群配置状态
ENDPOINTS=https://172.31.30.115:2379,https://172.31.29.250:2379,https://172.31.30.123:2379 |
增加 key
etcdctl put foo "hello world" |
查询 key
etcdctl get foo |
按照 key 的前缀查询
etcdctl get foo --prefix |
获取所有的 key
etcdctl get / --prefix |
删除 key
del
命令删除 key,失败返回 0,成功返回 1
etcdctl del key |
监听 key 的变更
使用 etcdctl watch
命令可以监听 key 的变动。每当监听的 key 有变更,命令会监听到变更情况
etcdctl watch foo |
使用选项 --prefix
可以监控指定内容开始的 key 的变更,以下命令监听以 foo
开头的 key 的变更情况
etcdctl watch foo --prefix |
etcd 集群备份及恢复
etcd
被设计为能承受机器失败。对于一个有 N 个成员的集群能容许 (N-1)/2
的持续失败,如果集群持续丢失超过 (N-1)/2
的成员,则它最终因法定成员(Quorum)不足而最终失败,一旦法定人数丢失,集群无法达到一致而因此无法继续接收更新。
为了从灾难失败中恢复,etcd v3
提供快照以下备份数据的方式
- 快照备份(
snapshot
) - 文件备份(
member/snap/db
)
快照备份
执行 etcd
集群快照可以作为 etc
键空间的持久备份,通过获取 etcd
成员的数据库的定期快照,etcd
集群可以被恢复到某个有已知良好状态的时间点。[1]
执行备份只需要在一个节点上执行,恢复时所有节点使用同一个备份进行恢复。
etcdctl snapshot save etcd-102310051318.db |
查看快照状态
etcdctl snapshot status etcd-102310051318.db --write-out=table |
文件备份
文件备份通过拷贝 etcd
数据目录下的 member/snap/db
实现。
恢复集群
集群恢复注意事项说明: [1]
- 所有的集群成员都必须使用同一份快照文件来恢复。
- 使用
etcdutl snapshot restore
恢复集群是需要创建新的etcd data directories
,或者将已有的目录删除,总之,一般需要一个新的集群或数据目录 - 集群恢复会覆盖一些快照元数据(特别是 member ID 和 Cluster ID)。集群成员会失去之前的 ID,此元数据覆盖可防止新成员无意中加入现有集群。因此,为了从快照恢复,必须启动一个新的逻辑集群
- 恢复时可能进行快照完整性检查。如果是
snampshot save
生成的快照,在snapshot restore
时会自动检查,如果是从数据目录拷贝的备份,因为没有integrity hash
无法校验,只能在恢复时使用参数--skip-hash-check
跳过完整性校验。 - 使用命令
snapshot restore
恢复时使用的参数--initial-cluster
要确保和启动集群时使用的一致。
- 参考以下命令,使用快照恢复,恢复时指定一个新的目录,需要在每个节点上执行
节点
k8s-master1
etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master1 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--initial-advertise-peer-urls=http://172.17.0.2:2380 \
--initial-cluster-token etcd
etcd \
--advertise-client-urls=http://172.17.0.2:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.2:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.2:2379 \
--listen-peer-urls=http://172.17.0.2:2380 \
--name=k8s-master1 \
--initial-cluster-token etcd节点
k8s-master2
etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master2 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--initial-advertise-peer-urls=http://172.17.0.3:2380 \
--initial-cluster-token etcd
etcd \
--advertise-client-urls=http://172.17.0.3:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.3:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.3:2379 \
--listen-peer-urls=http://172.17.0.3:2380 \
--name=k8s-master2 \
--initial-cluster-token etcd节点
k8s-master3
etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master3 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--initial-advertise-peer-urls=http://172.17.0.4:2380 \
--initial-cluster-token etcd
etcd \
--advertise-client-urls=http://172.17.0.4:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.4:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.4:2379 \
--listen-peer-urls=http://172.17.0.4:2380 \
--name=k8s-master3 \
--initial-cluster-token etcd
- 恢复后检查节点状态
etcdctl member list
119f945c36726355, started, k8s-master2, http://172.17.0.3:2380, http://172.17.0.3:2379, false
92892585e2b66fcc, started, k8s-master3, http://172.17.0.4:2380, http://172.17.0.4:2379, false
e18d752602ba842f, started, k8s-master1, http://172.17.0.2:2380, http://172.17.0.2:2379, false
etcdctl endpoint status --endpoints=$ENDPONTS --write-out=table
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://172.17.0.2:2379 | e18d752602ba842f | 3.5.3 | 106 MB | true | false | 2 | 13 | 13 | |
| http://172.17.0.3:2379 | 119f945c36726355 | 3.5.3 | 106 MB | false | false | 2 | 13 | 13 | |
| http://172.17.0.4:2379 | 92892585e2b66fcc | 3.5.3 | 106 MB | false | false | 2 | 13 | 13 | |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
etcdctl endpoint health --endpoints=$ENDPONTS --write-out=table
+------------------------+--------+------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+------------------------+--------+------------+-------+
| http://172.17.0.3:2379 | true | 4.125714ms | |
| http://172.17.0.2:2379 | true | 4.126622ms | |
| http://172.17.0.4:2379 | true | 4.280457ms | |
+------------------------+--------+------------+-------+
Kubernetes 中的 etcd 集群的恢复
在 堆叠(Stacked)etcd 拓扑 的架构下,etcd
集群由 Kubernetes 负责部署维护,Kubernetes 中的关键数据都存储于 etcd
集群中,假如 etcd
集群故障无法使用,则 Kubernetes 集群将完全无法使用,亦无法通过 Kubernetes 去管理恢复 etcd
集群。Kubernetes 堆叠(Stacked)etcd 拓扑 架构有以下特性:
- Kubernetes 堆叠(Stacked)
etcd
拓扑架构下的etcd
集群配置详情可以查看配置文件/etc/kubernetes/manifests/etcd.yaml
。 etcd
集群部署在 Kubernetes 集群的 Master 节点上,并且网络模式为hostNetwork: true
,即网络使用主机网络etcd
通过hostPath
方式挂载了 Kubernetes Master 主机节点目录/var/lib/etcd
,因此,etcd
节点的数据实际保留在 Kubernetes Master 主机节点目录/var/lib/etcd
etcd
集群启用了 TLS 通信,使用的证书通过hostPath
方式挂载了 Kubernetes Master 主机节点目录/etc/kubernetes/pki/etcd
此种故障,在保存有有效的 etcd
Snapshot 的情况下可以参考本示例进行恢复。
停止
kubelet
,重启docker
(或者其他 CRI)确保 Kubernetes 管理组件的 Pod 都处于停止状态,防止恢复etcd
时 Kubernetes 写入数据。此操作在所有 Kubernetes Master 节点上执行systemctl stop kubelet
mv /var/lib/etcd /var/lib/etcd.bak
systemctl restart docker
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4fbf7951781e 9fde607b81ff "kube-scheduler --au…" 4 hours ago Exited (0) 3 minutes ago k8s_kube-scheduler_kube-scheduler-k8s-master1_kube-system_cd7b8aef7d147b62355ca33773afd810_9
0b92dd3ee5ac 8380b6a23fb8 "kube-controller-man…" 4 hours ago Exited (2) 3 minutes ago k8s_kube-controller-manager_kube-controller-manager-k8s-master1_kube-system_a4ce6832517416c082459b497050f74c_12
02d550737d73 registry.k8s.io/pause:3.6 "/pause" 4 hours ago Exited (0) 3 minutes ago k8s_POD_etcd-k8s-master1_kube-system_80b158fbe6bff3c672202ca1b11d89fa_1
9bdf17effd5b registry.k8s.io/pause:3.6 "/pause" 4 hours ago Exited (0) 3 minutes ago k8s_POD_kube-scheduler-k8s-master1_kube-system_cd7b8aef7d147b62355ca33773afd810_7
6a484c46840f registry.k8s.io/pause:3.6 "/pause" 4 hours ago Exited (0) 3 minutes ago k8s_POD_kube-apiserver-k8s-master1_kube-system_f5f8d1635bc67efe34c36af301b7071d_4
4f606e7dfc32 registry.k8s.io/pause:3.6 "/pause" 4 hours ago Exited (0) 3 minutes ago k8s_POD_kube-controller-manager-k8s-master1_kube-system_a4ce6832517416c082459b497050f74c_8在 Kubernetes 的 Master 节点上,使用以下命令启动一个临时
etcd
容器,用来恢复备份数据。此处假设备份文件存在于主机目录/opt/k8s-backup/
。此操作在所有 Kubernetes Master 节点上执行docker run --rm --name etcd1 -it \
-v /var/lib/etcd/:/var/lib/etcd/ \
-v /opt/k8s-backup/:/opt/ \
-v /etc/kubernetes/pki/etcd/:/etc/kubernetes/pki/etcd/ \
k8s.gcr.io/etcd:3.5.3-0 sh恢复
etcd
备份数据。分别在对应节点上面的临时etcd
容器中执行恢复命令,使用的参数参考etcd
配置/etc/kubernetes/manifests/etcd.yaml
k8s-master1
节点:cd /opt/
etcdctl snapshot restore k8s-master1.etcd.202310051738.db \
--cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key \
--endpoints=https://127.0.0.1:2379 \
--name=k8s-master1 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master2=https://172.31.30.115:2380,k8s-master3=https://172.31.29.250:2380,k8s-master1=https://172.31.30.123:2380 \
--initial-advertise-peer-urls=https://172.31.30.123:2380 \
--initial-cluster-token etcdk8s-master2
节点:cd /opt/
etcdctl snapshot restore k8s-master1.etcd.202310051738.db \
--cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key \
--endpoints=https://127.0.0.1:2379 \
--name=k8s-master2 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master2=https://172.31.30.115:2380,k8s-master3=https://172.31.29.250:2380,k8s-master1=https://172.31.30.123:2380 \
--initial-advertise-peer-urls=https://172.31.30.115:2380 \
--initial-cluster-token etcdk8s-master3
节点:cd /opt/
etcdctl snapshot restore k8s-master1.etcd.202310051738.db \
--cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key \
--endpoints=https://127.0.0.1:2379 \
--name=k8s-master3 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master2=https://172.31.30.115:2380,k8s-master3=https://172.31.29.250:2380,k8s-master1=https://172.31.30.123:2380 \
--initial-advertise-peer-urls=https://172.31.29.250:2380 \
--initial-cluster-token etcd
启动
kubelet
,检查集群是否恢复正常,并检查集群数据是否恢复。恢复备份数据后,可以重启(删除)所有 Pod,避免 Pod 状态和etcd
中的数据不一致出现无法访问的问题systemctl start kubelet
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master1 Ready control-plane 339d v1.24.7
k8s-master2 Ready control-plane 339d v1.24.7
k8s-master3 Ready control-plane 339d v1.24.7
k8s-work1 Ready <none> 339d v1.24.7
k8s-work2 Ready <none> 339d v1.24.7
常见错误
cluster ID mismatch
使用同一份 Snapshot k8s-master1.etcd.202310051738.db
恢复集群的过程中,etcd
报错,恢复集群过程如下
- 节点
k8s-master1
上恢复etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master1 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380 \
--initial-advertise-peer-urls=http://172.17.0.2:2380
etcd \
--advertise-client-urls=http://172.17.0.2:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.2:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.2:2379 \
--listen-peer-urls=http://172.17.0.2:2380 \
--name=k8s-master1
- 节点
k8s-master2
上恢复etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master2 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380 \
--initial-advertise-peer-urls=http://172.17.0.3:2380
etcd \
--advertise-client-urls=http://172.17.0.3:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.3:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.3:2379 \
--listen-peer-urls=http://172.17.0.3:2380 \
--name=k8s-master2
恢复 k8s-master2
后报错 cluster ID mismatch
,这通常意味着正在尝试让两个不同的 etcd
集群中的节点相互通信,这是不被允许的
{"level":"warn","ts":"2023-10-06T05:13:08.818Z","caller":"rafthttp/stream.go:653","msg":"request sent was ignored by remote peer due to cluster ID mismatch","remote-peer-id":"69015be41c714f32","remote-peer-cluster-id":"10e5e39849dab251","local-member-id":"660aa483274d103a","local-member-cluster-id":"14dda1c29191f104","error":"cluster ID mismatch"} |
要在恢复时确保集群 ID 一致,需要确保每个节点使用相同的初始化配置(--initial-cluster
),修改恢复命令如下后正常
- 节点
k8s-master1
上恢复etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master1 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--initial-advertise-peer-urls=http://172.17.0.2:2380 \
--initial-cluster-token etcd
etcd \
--advertise-client-urls=http://172.17.0.2:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.2:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.2:2379 \
--listen-peer-urls=http://172.17.0.2:2380 \
--name=k8s-master1 \
--initial-cluster-token etcd - 节点
k8s-master2
上恢复etcdctl \
snapshot restore k8s-master1.etcd.202310051738.db \
--endpoints=http://127.0.0.1:2379 \
--name=k8s-master2 \
--data-dir /var/lib/etcd/ \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--initial-advertise-peer-urls=http://172.17.0.3:2380 \
--initial-cluster-token etcd
etcd \
--advertise-client-urls=http://172.17.0.3:2379 \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://172.17.0.3:2380 \
--initial-cluster=k8s-master1=http://172.17.0.2:2380,k8s-master2=http://172.17.0.3:2380,k8s-master3=http://172.17.0.4:2380 \
--listen-client-urls=http://127.0.0.1:2379,http://172.17.0.3:2379 \
--listen-peer-urls=http://172.17.0.3:2380 \
--name=k8s-master2 \
--initial-cluster-token etcd