kubernetes - day27

September 17, 2020

etcd 架構以及內部機制

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

客戶端對 etcd 做操作時只需簡單的使用 HTTP 方式即可存取。對於其數據可以想成是鍵值做一個儲存。同時 etcd 為了使用戶端訂閱數據變更,支援 watch 機制,透過 watch 即時獲取 etcd 中數據的增量更新,從而實現與 etcd 中的數據同步等業務邏輯。

etcd 主要提供了一下接口

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 來修改。從下面這個系統上預設元件來看,etcdcorednsapiservercontroller-managerscheduler 都運行在 master 上,我們所下達的 kubectl 相關命令都是 API Serverkubelete(每個節點都會安裝的代理) 發起。

$ 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 來說其元件都沒有高可用性,如果有實現的話 etcdAPI 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

參考資源

更新日期