Change Etcd cluster member ip
背景
Etcd是用于共享配置和服务发现的分布式、满足一致性的KV系统,受到Zookeeper启发,该项目是由CoreOS公司发起。目前在各种云环境中应用广泛,几个比较流行的云项目都采用了Etcd,如CloudFoundry、Kubernetes、Docker。Etcd采用Raft协议进行主节点的选举,并把相应的成员信息存储在各成员的db中。更多关于Etcd的详细介绍,可以在网上或者官方看到,这里不进行相关描述。
由于Kubernetes采用Etcd作为后端数据存储,如果Etcd出现问题,会导致整个Kubernetes集群的数据不一致,严重的甚至会导致集群不可用,因此需要掌握Etcd集群的常见问题解决方式,以便在该组件出现故障的时候,可以及时修复,从而保证Kubernetes集群的正常可用,不影响用户的使用。
如果Kubernetes集群部署完成后,更新整个集群所有节点的IP地址,当前Kubernetes的控制节点和Etcd成员节点在同一主机上运行,这也意味着如果修改Kubernetes控制节点的IP地址,需要对Etcd集群进行操作,以便Etcd集群可以使用新的IP地址进行通信。因此本文档重点介绍Etcd集群成员变更的两种方式。
成员变更解决方式
Etcd集群本身满足(n/2)+1
的成员容忍性。下面为集群大小对应的可容忍的异常成员数量。
集群大小 | Majority | 容忍数量 |
---|---|---|
1 | 1 | 0 |
2 | 2 | 0 |
3 | 2 | 1 |
4 | 3 | 1 |
5 | 3 | 2 |
6 | 4 | 2 |
7 | 4 | 3 |
8 | 5 | 3 |
9 | 5 | 4 |
目前我们的Kubernetes集群采用大多数是3节点的Etcd集群,因此允许一个节点失联。
下面详细描述下如何进行集群成员IP变更,因为我们的Etcd集群运行在容器中,采用Static Pod的方式由Kubelet进行管理,所以如果Etcd集群部署形态并非容器的话,请根据实际情况进行相应调整,关于etcdctl
的操作是一致的,没有区别。
我们仍然使用下面的三节点集群,所有节点IP地址如下:
成员名称 | 旧IP | 新IP |
---|---|---|
master1 | 192.168.100.10 | 192.168.110.10 |
master2 | 192.168.100.11 | 192.168.110.11 |
master3 | 192.168.100.12 | 192.168.110.12 |
在保证集群可用的情况进行成员变更
为满足对集群中节点进行IP地址变更的需求,在进行成员变更的时候,需要保证原有集群仍然可以对外进行服务,因此需要依次更换集群中的成员信息。
查看集群成员信息并检测集群是否健康。我们先进行master3节点的IP地址变更操作,看下如何在保证集群可用的情况下进行成员的IP地址变更。
$ ETCDCTL_API=3 etcdctl --endpoints=https://etcd.cluster.local.lb:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list
e2ef974167ea1d35, started, master1, https://192.168.100.10:2380, https://192.168.100.10:2379
1f2e59c3615624b3, started, master2, https://192.168.100.11:2380, https://192.168.100.11:2379
2430ba10b69efc5a, started, master3, https://192.168.100.12:2380, https://192.168.100.12:2379
$ /usr/bin/etcdctl --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --ca-file /etc/kubernetes/pki/etcd/ca.crt --endpoints https://etcd.cluster.local.lb:2379 cluster-health
member e2ef974167ea1d35 is healthy: got healthy result from https://192.168.100.10:2379
member 1f2e59c3615624b3 is healthy: got healthy result from https://192.168.100.11:2379
member 2430ba10b69efc5a is healthy: got healthy result from https://192.168.100.12:2379
我们更改master3
的IP地址192.168.100.12
为192.168.110.12
。下面是针对Etcd集群的变更操作。
- 重启master3上etcd的服务,可以看到该etcd成员正常启动。
docker ps -a -q --filter name=k8s_etcd | xargs -r docker rm --force --volumes
,可以看到etcd的容器被移除,并在1分钟之内会由Kubelet启动一个新的etcd服务。
可以通过docker ps -a -q --filter name=k8s_etcd | xargs docker logs
查看etcd的启动日志,启动会可以通过netstat -anp|grep 2379 | grep LISTEN
查看到etcd服务已经启动完成,并监听在2379端口。
- 登录到master1上,查看当前集群成员信息
$ ETCDCTL_API=3 etcdctl --endpoints=https://etcd.cluster.local.lb:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list
e2ef974167ea1d35, started, master1, https://192.168.100.10:2380, https://192.168.100.10:2379
1f2e59c3615624b3, started, master2, https://192.168.100.11:2380, https://192.168.100.11:2379
2430ba10b69efc5a, started, master3, https://192.168.100.12:2380, https://192.168.110.12:2379
我们可以看到集群中master3成员的client地址变为了新IP,而peer的地址仍然是旧IP,这是因为peer的信息存储在成员的db中,因此我们需要更改当前集群中master3的peer地址为新IP。
- 使用如下命令更改peer地址
ETCDCTL_API=3 etcdctl --endpoints=https://etcd.cluster.local.lb:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member update 2430ba10b69efc5a --peer-urls=https://192.168.110.12:2380
- 查看当前集群成员信息是否正确
$ ETCDCTL_API=3 etcdctl --endpoints=https://etcd.cluster.local.lb:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list
e2ef974167ea1d35, started, master1, https://192.168.100.10:2380, https://192.168.100.10:2379
1f2e59c3615624b3, started, master2, https://192.168.100.11:2380, https://192.168.100.11:2379
2430ba10b69efc5a, started, master3, https://192.168.110.12:2380, https://192.168.110.12:2379
可以看到master3的成员信息更新为新的IP。
要替换整个集群的成员信息,我们需要按上述步骤依次变更Etcd集群成员信息,该方式可以保证Etcd集群在成员变更的情况下,仍然可以对外提供服务。并且该方式对于整个集群风险偏低。
在不保证集群可用的情况下进行成员变更
在对集群中节点进行IP地址变更的过程中,还存在一种情况,那就是集群中所有节点事先修改了IP,在这种情况下,我们不能通过上面的依次变更成员的方式进行IP地址的变更,因为在这个时候,整个Etcd集群是不可用的,无法进行成员信息的在线变更,因此我们提供另一种变更方式来支持这种情况。
该方式主要是基于原有的Etcd集群数据,恢复出来一个新的Etcd集群,保证数据不丢失,因为在这个时候Etcd集群已经不可用了,并且所有成员信息全部进行了变更,相当于使用原有数据新建集群。
$ ETCDCTL_API=3 etcdctl --endpoints=https://etcd.cluster.local.lb:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list
e2ef974167ea1d35, started, master1, https://192.168.100.10:2380, https://192.168.100.10:2379
1f2e59c3615624b3, started, master2, https://192.168.100.11:2380, https://192.168.100.11:2379
2430ba10b69efc5a, started, master3, https://192.168.100.12:2380, https://192.168.100.12:2379
- 在任意一台成员节点生成现有Etcd集群的数据快照,并拷贝快照到其他成员节点
/tmp
目录下
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key snapshot save /tmp/snapshot.db
- 分别在所有成员节点主机上删除整个Etcd集群成员etcd数据目录
rm -rf <etcd数据目录>
- 分别在所有成员节点主机上执行快照恢复的命令
ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key snapshot restore snapshot.db --name <当前主机成员节点名称> --initial-cluster master1=https://<master1新IP>:2380,master2=https://<master2新IP>:2380,master3=https://<master3新IP>:2380 --initial-advertise-peer-urls=https://<当前主机成员节点IP>:2380 --data-dir=<etcd数据目录>
分别在所有成员节点修改Etcd服务的启动项中
--initial-cluster
、--initial-advertise-peer-urls
和--advertise-client-urls
的配置,该配置属于Etcd基本操作,不在此进行描述。分别在所有成员节点重启etcd服务,等待etcd成员正常启动。
docker ps -a -q --filter name=k8s_etcd | xargs -r docker rm --force --volumes
,Kubelet会启动一个新的etcd服务。
可以通过docker ps -a -q --filter name=k8s_etcd | xargs docker logs
查看etcd的启动日志,启动会可以通过netstat -anp|grep 2379 | grep LISTEN
查看到etcd服务已经启动完成,并监听在2379端口。
- 登录到任意一台成员主机上,查看当前集群成员信息
$ ETCDCTL_API=3 etcdctl --endpoints=https://etcd.cluster.local.lb:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key member list
e2ef974167ea1d35, started, master1, https://192.168.110.10:2380, https://192.168.110.10:2379
1f2e59c3615624b3, started, master2, https://192.168.110.11:2380, https://192.168.110.11:2379
2430ba10b69efc5a, started, master3, https://192.168.110.12:2380, https://192.168.110.12:2379
我们可以看到集群的client和peer地址变为了新的IP,使用etcdctl检测集群是否健康。
$ /usr/bin/etcdctl --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --ca-file /etc/kubernetes/pki/etcd/ca.crt --endpoints https://etcd.cluster.local.lb:2379 cluster-health
member e2ef974167ea1d35 is healthy: got healthy result from https://192.168.110.10:2379
member 1f2e59c3615624b3 is healthy: got healthy result from https://192.168.110.11:2379
member 2430ba10b69efc5a is healthy: got healthy result from https://192.168.110.12:2379
至此整个集群成员IP变更就完成了,并且集群可以正常对外提供服务。
总结
上面介绍了两种不同的方式来进行Etcd集群成员IP变更,在Kubernetes集群中,Etcd是被严重依赖的,因此对于Etcd集群的任何操作,我们都需要小心谨慎,否则可能会导致整个集群的崩溃,从而使得影响面无限扩大,因此建议如非必要,切勿进行上述的第二种方式进行集群成员的变更,因为快照数据一旦损坏,整个集群需要重建,建议采用第一种方式,该方式可以保证在修改的成员出现问题的时候,集群仍然是可用的,从而如果在变更的成员出现问题无法恢复的情况下,集群仍然可以进行节点添加、删除的操作,来保证集群的高可用。