etcd 架構以及內部機制

一個 etcd 的集群節點之間透過 Raft 一致性演算法完成分散式一致性協同,從圖中可以知道會有一個 leader,而當該 leader 故障時,會自動再選取其它節點做為 leader,同時也完成數據的同步,對於客戶端來說只要選取任一節點即可做讀寫操作,內部的狀態和數據協同由 etcd 自身完成。etcd 中還有一個 quorum 概念,其表示容忍故障的數量。

客戶端對 etcd 做操作時只需簡單的使用 HTTP 方式即可存取。對於其數據可以想成是鍵值做一個儲存。同時 etcd 為了使用戶端訂閱數據變更,支援 watch 機制,透過 watch 即時獲取 etcd 中數據的增量更新,從而實現與 etcd 中的數據同步等業務邏輯。
etcd 主要提供了一下接口
- Put(key, value), Del(key, value)
- Get(key), Get(keyFrom, keyEnd)
- Watch(key/keyPrefix)
- Transactions(if/then/else ops.).Commit()
- Leases: Grant/Revoke/KeepAlive
etcd 版本機制
etcd 中有 term 的概念,表示整個集群 Leader 的任期。只要 Leader 發生變化就會加 1。再者就是 revision,表示全域數據版本,當數據發生變更,包括創建、修改、刪除等,其 revision 都會加 1。不過 Leader 發生切換時 revision 是延續的。
使用場景
Server Discovery (Naming Service)

Distributed Coordination: leader election

Distributed Coordination

Kubernetes 中的 etcd
在 Kubernetes 中元件間的通訊都是藉由 API Server 通訊,而 API Server 是和 etcd 通訊的唯一元件,因此在 Kubernetes 上所有狀態都是藉由 API Server 來修改。從下面這個系統上預設元件來看,etcd、coredns、apiserver、controller-manager 和 scheduler 都運行在 master 上,我們所下達的 kubectl 相關命令都是 API Server 向 kubelete(每個節點都會安裝的代理) 發起。
$ kubectl get pods -n kube-system -o custom-columns=POD:metadata.name,NODE:spec.nodeName
POD NODE
coredns-66bff467f8-5pfbz master
coredns-66bff467f8-v4txv master
etcd-master master
kube-apiserver-master master
kube-controller-manager-master master
kube-flannel-ds-amd64-gljsn master
kube-flannel-ds-amd64-s58vt node01
kube-flannel-ds-amd64-w2q8g node02
kube-proxy-fm749 master
kube-proxy-xpt4b node01
kube-proxy-xxlnx node02
kube-scheduler-master master
對於只有一個 master 來說其元件都沒有高可用性,如果有實現的話 etcd 和 API Server 將可以並行執行,相對的其它元件只有一個會做回應,其餘都是備援狀態。
如何使用 etcd
etcd 是一個分散式以 Key-value 做儲存的軟體,etcd 在 Kubernetes 中是唯一儲存集群狀態和一些數據的地方,那為何只有 API Server 可以對 etcd 讀寫?它避免了 Optimistic Concurrency Control 或是增強驗證系統,這樣替換元件時也方便。
儲存在 etcd 的資源
儲存在 etcd 中的資源依照目前不同版本有不一樣的做法,在第二版會是以檔案系統方式建立,而第三版是以 / 做為取代目錄。這邊補充一個 etcd 使用 RAFT 演算法保證一致性。
$ sudo apt install etcd-client # 安裝套件
這邊使用的環境是 kubeadm 架設的,而預設 etcd 使用 tls。
$ sudo ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key get /registry/namespaces/default -w=json | jq .
{
"header": {
"cluster_id": 14991974125033499000,
"member_id": 13655367627031355000,
"revision": 205622,
"raft_term": 2
},
"kvs": [
{
"key": "L3JlZ2lzdHJ5L25hbWVzcGFjZXMvZGVmYXVsdA==",
"create_revision": 152,
"mod_revision": 152,
"version": 1,
"value": "azhzAAoPCgJ2MRIJTmFtZXNwYWNlErIBCpcBCgdkZWZhdWx0EgAaACIAKiQwN2ZjNjg5NS1lZDY2LTRlZDMtYWFkYS03MDRiZThmN2FjYjcyADgAQggInrvu+QUQAHoAigFPCg5rdWJlLWFwaXNlcnZlchIGVXBkYXRlGgJ2MSIICJ677vkFEAAyCEZpZWxkc1YxOh0KG3siZjpzdGF0dXMiOnsiZjpwaGFzZSI6e319fRIMCgprdWJlcm5ldGVzGggKBkFjdGl2ZRoAIgA="
}
],
"count": 1
}
$ sudo ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key get /registry/namespaces/ --prefix -w=json | jq . # --prefix 查看子目錄
這邊的 Key 使用 base64 編碼,解碼後就可以知道其結構
$ echo L3JlZ2lzdHJ5L25hbWVzcGFjZXMvZGVmYXVsdA== | base64 -d
/registry/namespaces/default
參考資源
更新日期
- 2020-11-05 新增 etcd 相關小細節