Etcd数据迁移

本文讲述从一个正在运行的 etcd 上,将数据迁移到一个包含三台 etcd 服务器组成的集群上,其中包含一些故障恢复和数据迁移的方法以及高可用 etcd 集群搭建方式的介绍。

数据迁移

在 inf-platform53 机器上运行着一个 etcd 服务器,其 data-dir 为 /var/lib/etcd/。我们要以 /var/lib/etcd 中的数据为基础,搭建一个包含三个节点的高可用的 etcd 集群,三个节点的主机名分别为:

1
2
3
inf-platform53
inf-platform56
inf-platform60

初始化一个新的集群

我们先分别在上述三个节点上创建 /home/work/etcd/data-dir/ 文件夹当作 etcd 集群每个节点的数据存放目录。然后以 inf-platform60 节点为起点创建一个单节点的 etcd 集群,启动脚本 force-start-etcd.sh 如下:

1
2
3
4
5
#!/bin/bash

# Don't start it unless etcd cluster has a heavily crash !

../bin/etcd --name etcd2 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://inf-platform60:2379,http://inf-platform60:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://inf-platform60:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://inf-platform60:2380 --force-new-cluster > ./log/etcd.log 2>&1

这一步的 –force-new-cluster 很重要,可能是为了抹除旧 etcd 的一些属性信息,从而能成功的创建一个单节点 etcd 的集群。

这时候通过

1
etcdctl member list

查看 peerURLs 指向的是不是 http://inf-platform60:2380 ? 如果不是,需要更新这个 etcd 的 peerURLs 的指向,否则这样在加入新的节点时会失败的。我们手动更新这个 etcd 的 peerURLs 指向

1
etcdctl member update ce2a822cea30bfca http://inf-platform60:2380

添加etcd1成员

然后添加 inf-platform56 节点上的 etcd1 成员

1
etcdctl member add etcd1 http://inf-platform56:2380

注意要先添加 etcd1 成员后,再在 inf-platform56 机器上启动这个 etcd1 成员

这时候我们登陆上 inf-platform56 机器上启动这个 etcd1 实例,启动脚本 force-start-etcd.sh 如下:

1
2
3
4
5
#!/bin/bash

# Don't start it unless etcd cluster has a heavily crash !

../bin/etcd --name etcd1 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://inf-platform56:2379,http://inf-platform56:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://inf-platform56:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://inf-platform60:2380,etcd1=http://inf-platform56:2380 --initial-cluster-state existing > ./log/etcd.log 2>&1

注意在这个节点上我们先把 data-dir 文件夹中的数据删除(如果有内容的情况下),然后设置 --initial-cluster--initial-cluster-state

添加 etcd0 成员

这时候我们可以通过

1
etcdctl member list

观察到我们新加入的节点了,然后我们再以类似的步骤添加第三个节点 inf-platform53 上 的 etcd0 实例

1
etcdctl member add etcd0 http://inf-platform53:2380

然后登陆到 inf-platform53 机器上启动 etcd0 这个实例,启动脚本 force-start-etcd.sh 如下:

1
2
3
4
5
#!/bin/bash

# Don't start it unless etcd cluster has a heavily crash !

../bin/etcd --name etcd0 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://inf-platform53:2379,http://inf-platform53:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://inf-platform53:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://inf-platform60:2380,etcd1=http://inf-platform56:2380,etcd0=http://inf-platform53:2380 --initial-cluster-state existing > ./log/etcd.log 2>&1

过程同加入 etcd1 的过程相似,这样我们就可以把单节点的 etcd 数据迁移到一个包含三个 etcd 实例组成的集群上了。

大体思路

先通过 --force-new-cluster 强行拉起一个 etcd 集群,抹除了原有 data-dir 中原有集群的属性信息(内部猜测),然后通过加入新成员的方式扩展这个集群到指定的数目。

高可用etcd集群方式(可选择)

上面数据迁移的过程一般是在紧急的状态下才会进行的操作,这时候可能 etcd 已经停掉了,或者节点不可用了。在一般情况下如何搭建一个高可用的 etcd 集群呢,目前采用的方法是用 supervise 来监控每个节点的 etcd 进程。

在数据迁移的过程中,我们已经搭建好了一个包含三个节点的 etcd 集群了,这时候我们对其做一些改变,使用supervise 重新拉起这些进程。

首先登陆到 inf-platform60 节点上,kill 掉 etcd 进程,编写 etcd 的启动脚本 start-etcd.sh,其中 start-etcd.sh 的内容如下:

1
2
3
#!/bin/bash

../bin/etcd --name etcd2 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://inf-platform60:2379,http://inf-platform60:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://inf-platform60:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://inf-platform60:2380,etcd1=http://inf-platform56:2380,etcd0=http://inf-platform53:2380 --initial-cluster-state existing > ./log/etcd.log 2>&1

然后使用 supervise 执行 start-etcd.sh 这个脚本,使用 supervise 启动 start-etcd.sh 的启动脚本 etcd_control 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/sh

if [ $# -ne 1 ]; then
echo "$0: start|stop"
fi


work_path=`dirname $0`
cd ${work_path}
work_path=`pwd`

supervise=${work_path}/supervise/bin/supervise64.etcd
mkdir -p ${work_path}/supervise/status/etcd


case "$1" in
start)
killall etcd supervise64.etcd
${supervise} -f "sh ./start-etcd.sh" \
-F ${work_path}/supervise/conf/supervise.conf \
-p ${work_path}/supervise/status/etcd
echo "START etcd daemon ok!"
;;
stop)
killall etcd supervise64.etcd
if [ $? -ne 0 ]
then
echo "STOP etcd daemon failed!"
exit 1
fi
echo "STOP etcd daemon ok!"

这里为什么不直接用 supervise 执行 etcd 这个命令呢,反而以一个 start-etcd.sh 脚本的形式启动这个 etcd 呢?原因在于我们需要将 etcd 的输出信息重定向到文件中,如果直接在 supervise 的 command 进行重定向,将发生错误。

分别登陆到以下两台机器

  • inf-platform56
  • inf-platform53

上进行同样的操作,注意要针对每个节点的不同修改对应的etcd name 和 peerURLs 等。

常见问题

1、etcd 读取已有的 data-dir 数据而启动失败,常常表现为cluster id not match什么的

可能原因是新启动的 etcd 属性与之前的不同,可以尝 --force-new-cluster 选项的形式启动一个新的集群

2、etcd 集群搭建完成后,通过 kubectl get pods 等一些操作发生错误的情况

目前解决办法是重启一下 apiserver 进程

3、还是 etcd启动失败的错误,大多数情况下都是与data-dir 有关系,data-dir 中记录的信息与 etcd启动的选项所标识的信息不太匹配造成的

如果能通过修改启动参数解决这类错误就最好不过的了,非常情况下的解决办法:

  • 一种解决办法是删除data-dir文件
  • 一种方法是复制其他节点的data-dir中的内容,以此为基础上以 --force-new-cluster 的形式强行拉起一个,然后以添加新成员的方式恢复这个集群,这是目前的几种解决办法