13 庖丁解牛:etcd

整体概览

+———————————————————-+ Master   +————————-+   +——-> API Server <——–+               v +————————-+ v   +—————-+ ^ +——————–+                   Scheduler     Controller Manager                   +—————-+ v +——————–+   +——————————————————+             Cluster state store             +——————————————————+ +———————————————————-+

在第 3 节《宏观认识:整体架构》 中,我们也认识到了

etcd 的存在,知道了 Master 是 K8S 是集群的大脑,而

etcd 则是大脑的核心。为什么这么说?本节我们一同来看看

etcd 为何如此重要。

## etcd 是什么

先摘录官方文档的一句说明: etcd is a consistent distributed key-value store. Mainly used as a separate coordination service, in distributed systems. And designed to hold small amounts of data that can fit entirely in memory.

etcd 是由 CoreOS 团队发起的一个分布式,强一致的键值存储。它用 Go 语言编写,使用

Raft 协议作为一致性算法。多数情况下会用于分布式系统中的服务注册发现,或是用于存储系统的关键数据。

## etcd 有什么作用

etcd 在 K8S 中,最主要的作用便是其高可用,强一致的键值存储以及监听机制。

kube-apiserver 收到对应请求经过一系列的处理后,最终如果是集群所需要存储的数据,便会存储至

etcd 中。主部分主要是集群状态信息和元信息。

我们来实际操作 K8S 集群中的

etcd 看下真实情况。

  • 查找集群中的

etcd Pod /# 默认集群中的 etcd 会放到 kube-system Namespace 中 master $ kubectl -n kube-system get pods | grep etcd etcd-master 1/1 Running 0 1h

  • 进入该 Pod 并查看

etcd 集群的

member master $ kubectl -n kube-system exec -it etcd-master sh / /# ETCDCTL_API=3 etcdctl –key=/etc/kubernetes/pki/etcd/server.key –cert=/etc/kubernetes/pki/etcd/server.crt –cacert=/etc/kubernetes/pki/etcd/ca.crt member list a874c87fd42044f, started, master, https://127.0.0.1:2380, https://127.0.0.1:2379

这里由于在 K8S 1.11.3 中默认使用的是

etcd 3.2 版本,所以需要加入

ETCDCTL_API=3 的环境变量,且

etcd 从 2 到 3 很明显的一个变化也是使用上的变化,在 2 中是 HTTP 接口的。

我们通过传递证书等相关参数进去,完成校验,查看

member 。

  • 查看存储的元信息

etcd 中存储的 K8S 集群元信息基本都是

/registry 下,我们可通过下面的方式进行查看 / /# ETCDCTL_API=3 etcdctl –key=/etc/kubernetes/pki/etcd/server.key –cert=/etc/kubernetes/pki/etcd/server.crt –cacert=/etc/kubernetes/pki/etcd/ca.crt get /registry –prefix –keys-only /registry/apiregistration.k8s.io/apiservices/v1. /registry/clusterroles/system:aggregate-to-admin /registry/configmaps/kube-public/cluster-info /registry/masterleases/172.17.0.53 /registry/namespaces/default /registry/namespaces/kube-public /registry/namespaces/kube-system /registry/pods/kube-system/etcd-master /registry/pods/kube-system/kube-apiserver-master /registry/ranges/serviceips /registry/ranges/servicenodeports … /# 篇幅原因,删掉了很多输出

可以看到有各种类型的资源。我们直接以 Namespaces 为例。

  • 查看 Namespaces 信息 / /# ETCDCTL_API=3 etcdctl –key=/etc/kubernetes/pki/etcd/server.key –cert=/etc/kubernetes/pki/etcd/server.crt –cacert=/etc/kubernetes/pki/etcd/ca.crt get /registry/namespaces –prefix –keys-only /registry/namespaces/default /registry/namespaces/kube-public /registry/namespaces/kube-system

  • 使用

kubectl 创建名为

moelove 的 Namespaces master $ kubectl create ns moelove namespace/moelove created

  • 查看 Namespaces 信息 / /# ETCDCTL_API=3 etcdctl –key=/etc/kubernetes/pki/etcd/server.key –cert=/etc/kubernetes/pki/etcd/server.crt –cacert=/etc/kubernetes/pki/etcd/ca.crt get /registry/namespaces –prefix –keys-only /registry/namespaces/default /registry/namespaces/kube-public /registry/namespaces/kube-system /registry/namespaces/moelove

发现刚创建的

moelove 的 Namespaces 已经在

etcd 中了。

## etcd 是如何被使用的

首先,在

staging/src/k8s.io/apiserver/pkg/server/options/etcd.go 中,存在一处声明: var storageTypes = sets.NewString( storagebackend.StorageTypeUnset, storagebackend.StorageTypeETCD2, storagebackend.StorageTypeETCD3, )

在 1.13 发布时,etcd 2 的相关代码已经移除,其中就包含上面声明中的 storagebackend.StorageTypeETCD2

这里是在过渡期间为了同时兼容

etcd 2 和 3 而增加的。

我们来看下实际对各类资源的操作,还是以对

Namespace 的操作为例:代码在

pkg/registry/core/namespace/storage/storage.go 中,

比如,

Get : func (r /REST) Get(ctx context.Context, name string, options /metav1.GetOptions) (runtime.Object, error) { return r.store.Get(ctx, name, options) }

REST 则是这样定义的:

type REST struct { store /genericregistry.Store status /genericregistry.Store }

通过

REST 实现了一个

RESTStorage ,实际使用时,也是调用了

staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go 对接口的封装。

func (e /Store) Get(ctx context.Context, name string, options /metav1.GetOptions) (runtime.Object, error) { obj := e.NewFunc() key, err := e.KeyFunc(ctx, name) if err != nil { return nil, err } if err := e.Storage.Get(ctx, key, options.ResourceVersion, obj, false); err != nil { return nil, storeerr.InterpretGetError(err, e.qualifiedResourceFromContext(ctx), name) } if e.Decorator != nil { if err := e.Decorator(obj); err != nil { return nil, err } } return obj, nil }

在该处实现了对各类基本方法的封装,各种资源类型都会统一去调用。而更上层则是对

storagebackend 的统一封装,最终会调用

etcd 客户端的实现完成想对应的操作,这里就不再多展开了。

总结

在本节中,我们介绍了

etcd 以及它在 K8S 中的作用以及如何使用。我们还介绍了如何通过

etcdctl 工具去操作

etcd 。

在某些极端情况下,也许你需要通过直接操作

etcd 集群去变更数据,这里没有介绍所有的操作命令,感兴趣的可以自行通过下方的链接看官方文档进行学习。

但通常情况下,不建议直接操作

etcd ,除非你已经明确自己在做什么。

另外,由于

etcd 集群使用

Raft 一致性算法,通常情况下

etcd 集群需要部署奇数个节点,如 3,5,7 等。

etcd 集群维护也相对容易,很容易可以做成高可用集群。(这也是保障 K8S 集群高可用的重要一环)

学习了

etcd 之后,下节我们来学习同样很重要的一个组件

Controller Manager ,学习它是如何保障集群符合预期状态的。

参考链接

参考资料

https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/Kubernetes%20%e4%bb%8e%e4%b8%8a%e6%89%8b%e5%88%b0%e5%ae%9e%e8%b7%b5/13%20%e5%ba%96%e4%b8%81%e8%a7%a3%e7%89%9b%ef%bc%9aetcd.md