英文原文:A Closer Look at Etcd: The Brain of a Kubernetes Cluster
譯文原文:[譯]走進Kubernetes集群的大腦:Etcd
譯者:野生程序元
Etcd是Kubernetes用於存儲集群各種狀態信息(配置信息,運行)一個很重要的組件,這篇文章,我們帶領大家掀開Etcd的神秘面紗,理解他是如何存儲這些各種各樣的碎片信息的。
Etcd的概況
Etcd 是一個分布式的,依賴key-value存儲的,最重要的分布式數據存儲系統
-- etcd.io
在Kubernetes的世界里面,etcd是服務發現,集群狀態存儲以及其配置的基石。
Etcd以集群部署,節點間通信是通過Raft算法處理。在生產環境中,集群包含至少3個節點。在 thesecretlivesofdata.com/ 中使用動畫很好地地解釋了Raft算法如何運作以及整個集群的生命周期,包含以下幾點
- leader節點的選舉
- 日志的復制與同步
Kubernetes中的Etcd
在Kubernetes集群的背景下,etcd實例可以作為Pod被部署在master節點上。下面是我們這篇文章會使用的Kubernetes模型。
如果想增加安全校驗與彈性伸縮的功能的話,也可以將etcd部署成一個內部集群。
下面這個時序圖來自Hepio的博客,展示了當一個Pod被創建的時候,Kubernetes內部模塊之間的處理流程,形象地闡述了API Server和etcd之間的相互作用。
Kubernetes測試集群
這個部分我們使用在DigitalOcean的kubeadm
創建一個3節點的Kubernetes測試集群,選擇weavenet
作為網絡附加組件。這個集群的etcd運行在master節點上。我們並沒有配置一個真實環境的HA集群,但已經足夠我們去探索etcd的數據存儲功能了。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION node-01 Ready master 56m v1.15.2 node-02 Ready <none> 2m17 v1.15.2 node-03 Ready <none> 2m17 v1.15.2
Etcd Pod
首先,我們將集群中所有正在運行的Pods先列出來:
$ kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTART AGE kube-system coredns-5c98db65d4–5kjjv 1/1 Running 0 57m kube-system coredns-5c98db65d4–88hkq 1/1 Running 0 57m kube-system etcd-node-01 1/1 Running 0 56m kube-system kube-apiserver-node-01 1/1 Running 0 56m kube-system kube-controller-manager-node-01 1/1 Running 0 56m kube-system kube-proxy-7642v 1/1 Running 0 3m kube-system kube-proxy-jsp4r 1/1 Running 0 3m kube-system kube-proxy-xj8qm 1/1 Running 0 57m kube-system kube-scheduler-node-01 1/1 Running 0 56m kube-system weave-net-2hvbx 2/2 Running 0 87s kube-system weave-net-5mrjl 2/2 Running 0 87s kube-system weave-net-c76fx 2/2 Running 0 87s
當一個集群剛被初始化的時候,只有在namespace為kube-system
中的Pod是運行狀態的。這些Pod是用來作為集群的任務管理的。我們比較關心的Pod是etcd-node-01
,他是一個ectd的實例,用於存儲集群狀態。
我們運行一個shell命令,進入到這個Pod里面並且查看這個ctcd container的配置
通過使用--advertise-client-urls
標識我們可以拿到所有的key/value對,通過etcdctl
命令將他們保存到etcd-kv.json
中
$ ADVERTISE_URL="https://134.209.178.162:2379" $ kubectl exec etcd-node-01 -n kube-system -- sh -c \ "ETCDCTL_API=3 etcdctl \ --endpoints $ADVERTISE_URL \ --cacert /etc/kubernetes/pki/etcd/ca.crt \ --key /etc/kubernetes/pki/etcd/server.key \ --cert /etc/kubernetes/pki/etcd/server.crt \ get \"\" --prefix=true -w json" > etcd-kv.json
我們快速查看一下這個文件,所有的key對應的values,並且所有都編碼成了base64。
我們先獲取所有的key到一個text文件里面看看他們都長什么樣子,我將所有的key都列出來了,所以有點點長。
$ for k in $(cat etcd-kv.json | jq '.kvs[].key' | cut -d '"' -f2); do echo $k | base64 --decode; echo; done /registry/apiregistration.k8s.io/apiservices/v1. /registry/apiregistration.k8s.io/apiservices/v1.apps /registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.autoscaling /registry/apiregistration.k8s.io/apiservices/v1.batch /registry/apiregistration.k8s.io/apiservices/v1.coordination.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.scheduling.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.apps /registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.batch # 后面有很多,已省略 ...
上面顯示了一共342個定義在配置文件中的key,包含所有在集群里面的資源:
- Nodes
- Namespaces
- ServiceAccounts
- Roles,RolesBindings, ClusterRoles/ClusterRoleBindings
- ConfigMaps
- Secrets
- Workloads: Deployments, DaemonSets, Pods, …
- Cluster’s certificates
- The resources within each apiVersion
- The events that bring the cluster in the current state
如果我們選擇以上其中一個key,我們可以得到具體與之關聯的value通過以下命令:
$ kubectl exec etcd-node-01 -n kube-system —- sh -c \ "ETCDCTL_API=3 etcdctl \ --endpoints $ADVERTISE_URL \ --cacert /etc/kubernetes/pki/etcd/ca.crt \ --key /etc/kubernetes/pki/etcd/server.key \ --cert /etc/kubernetes/pki/etcd/server.crt \ get \"KEY\" -w json"
舉個例子,我們想獲得/registry/deployments/kube-system/coredns
這個key的value
如果我們將這個對應的value解碼出來發現信息其實可讀性不高,一些圖表不能被正常解碼顯示,但當然,Kubernetes內部是知道如何正確處理他們的。
從這個結果上看,我們可以推斷出這個key是用來存儲credns
這個Pod的規則以及部署狀態的。
創建一個Pod
讓我們一起來創建一個Pod,看看集群的狀態修改了什么以及有什么新的key的增加。
$ cat <<EoF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: www spec: containers: - name: nginx image: nginx:1.16-alpine EoF
和之前一樣的命令,我們獲取所有的key並保存在etcd-kv-after-nginx-pod.json
中。快速對比一下我們創建Pod之前的key列表和我們創建完www
Pod以后多了什么信息。
> /registry/events/default/www.15b9e3051648764f > /registry/events/default/www.15b9e3056b8ce3f0 > /registry/events/default/www.15b9e306918312ea > /registry/events/default/www.15b9e306a32beb6d > /registry/events/default/www.15b9e306b5892b60 > /registry/pods/default/www
5個event以及一個pod被創建了,並且看上去也十分合理。我們更深入地看一下,從解碼event key所對應的value開始,按照時間排序,我們可以看到他們做了下面的事情:
- 成功指派
default/www
到node-02
- 拉取鏡像
nginx:1.16-alpine
- 成功拉取鏡像
nginx:1.16-alpine
- 創建
nginx
container - 啟動這個container
這些事件可以通過下面命令查看:
kubectl describe pod www
最后一個key,/registry/pods/default/www
,提供了這個新創建的pod的所有信息
- 最后使用的配置
- 關聯的token
- 狀態
- ...
(依然解碼出來可讀性很糟糕。)
總結
這篇文章的目的不是深入etcd,而是解釋了一小部分Kubernetes內部包含了什么信息以及這些信息是怎么被組織起來的。希望能填補你對Kubernetes的一小片空白。