备份方式:Jenkins触发每小时的定时任务,通过调取ansible的playbook进行etcd集群的数据备份和上传,默认只备份集群中的非leader成员,避免leader成员压力过大。将备份数据上传到对应的公有云对象存储,分别上传到两个不同的对象存储的目录下,以适配不同目录下的不同生命周期规则,a目录每小时上传,生命周期为保留近3天的每小时的数据备份;b目录为只有当时间为0点、12点才进行上传,生命周期为保留近15天的数据备份,每天有2次备份。
备份命令:
/usr/local/bin/etcdctl --endpoints {{ ansible_default_ipv4.address }}:2379 snapshot save {{ local_tar_dir }}{{ dump_name }}
#ansible_default_ipv4.address:本机的IP地址
#local_tar_dir:本地的保存路径
#dump_name:备份名字
生产环境中,经常遇到etcd集群出现单节点故障或者集群故障。针对这两种情况,进行故障修复。以下为介绍etcd的集群全部节点故障时,故障应急的恢复手册
#obs华为云
sudo /usr/local/bin/obsutil ls obs://jws2-live-cn-backup-01/db-etcd/2024-03-28/05/ -s | grep "_master"
sudo /usr/local/bin/obsutil cp {{ first_tarball }} /tmp/snapshot.db
#gcp谷歌云
/bin/gsutil ls gs://{{cloud_backup_bucket}}/db-etcd/{{now_date}}/{{now_hour}}/
/bin/gsutil cp {{ backup_file.stdout }} /tmp/snapshot.db
执行jenkins任务,或者手动执行命令
/usr/local/bin/etcdctl --endpoints {{ ansible_default_ipv4.address }}:2379 snapshot save {{ local_tar_dir }}{{ dump_name }}
#{{ local_tar_dir }}{{ dump_name }}:备份保存的目标目录和文件名
sudo systemctl stop etcd
#移除原有目录
sudo mv /opt/etcd/etcd-data /opt/etcd/etcd-data_bak
#创建新目录
sudo mkdir /opt/etcd/etcd-data
建议使用etcdutl命令
先将etcdutl命令移动
sudo cp /opt/etcd/etcd-data/etcd-v3.5.0-linux-amd64/etcdutl /usr/local/bin/etcdutl
在每台机器上都需要进行还原,从快照恢复时,您可以直接将新成员信息提供到数据存储中
$ etcdutl snapshot restore snapshot.db \
--name m1 \
--initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls http://host1:2380 \
--data-dir=/opt/etcd/etcd-data
$ etcdutl snapshot restore snapshot.db \
--name m2 \
--initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls http://host2:2380 \
--data-dir=/opt/etcd/etcd-data
$ etcdutl snapshot restore snapshot.db \
--name m3 \
--initial-cluster m1=http://host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls http://host3:2380 \
--data-dir=/opt/etcd/etcd-data
启动etcd集群
sudo systemctl start etcd
检查每个etcd的数据大小和成员信息
sudo etcdctl --endpoints=http://192.168.1.5:2380,http://192.168.0.142:2380,http://192.168.1.175:2380,http://192.168.1.99:2380,http://192.168.0.70:2380 endpoint status -w table
sudo etcdctl member list
检查日志是否有异常
etcd集群还原有一些坑,应当慎重执行还原操作!
当使用备份进行整个集群的还原时,集群间的数据不会自动同步,必须每台都要进行还原,切记!一定要使用同一份备份数据进行所有节点的还原。
第一次进行测试时,共有三节点,只将节点1进行了还原,2、3节点没有进行还原,2、3节点也没有数据,但是集群依然可以启动,并且2、3节点上也没有数据,集群的运行状态正常,还可以正常对外提供服务,很是诡异。
去集群get某个key,只会有三分之一的概率会获取到。也是说raft协议在这时并不会生效,这时候在写入key,集群间同步正常,可以正常获取到这个key。
因为我们在还原集群的时候指定了新的元数据,还原后的集群可以认为是一个新的集群,通过上述的情况可知,即便是集群的三个节点恢复了不同的数据,集群也不会进行数据校验,当集群运行后,raft协议才会生效,raft只会同步“新”集群后写入的数据。
生产环境中,经常遇到etcd集群出现单节点故障或者集群故障。针对这两种情况,进行故障修复。本文介绍etcd的单节点故障时,故障应急的恢复手册
由于etcd的raft协议,整个集群能够容忍的故障节点数为(n-1)/ 2,因此在单个节点故障时,单个集群的仍然可用,不会影响业务的读写。
整体的恢复流程如下
集群member rmove异常节点–>异常节点删除脏数据–>集群member add节点–>集群完成数据同步并恢复
通过member remove命令删除异常节点,此时整个集群只有2个节点,不会触发master重新选主,集群正常运行。
export ETCDCTL_API=3
export ETCD_ENDPOINTS=192.168.92.128:2379,192.168.92.129:2379,192.168.92.130:2379
etcdctl --endpoints=$ETCD_ENDPOINTS --write-out=table member list
etcdctl --endpoints=$ETCD_ENDPOINTS --write-out=table endpoint status
MEMBER_ID=278c654c9a6dfd3b
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 \
member remove ${MEMBER_ID}
#移除原有目录
sudo mv /opt/etcd/etcd-data /opt/etcd/etcd-data_bak
#创建新目录
sudo mkdir /opt/etcd/etcd-data
通过如下命令,将异常节点添加到集群中,等对应的节点启动后,就会自动完成集群数据同步和选主
export ETCDCTL_API=3
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_3=etcd-node-3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.16 # 故障成员
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379 \
member add ${NAME_3} \
--peer-urls=http://${HOST_3}:2380
注意:
由于etcd的数据已经被删除,因此当前节点重启时,从其他的节点获取数据,因此需要调整参数–initial-cluster-state,从new改成existing
TOKEN=my-etcd-token-1
CLUSTER_STATE=existing
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_3=etcd-node-3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.16 # 故障成员
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 \
--listen-peer-urls http://${THIS_IP}:2380 \
--advertise-client-urls http://${THIS_IP}:2379 \
--listen-client-urls http://${THIS_IP}:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state existing \
--initial-cluster-token ${TOKEN}
export ETCDCTL_API=3
export ETCD_ENDPOINTS=10.240.0.13:2379,10.240.0.14:2379,10.240.0.16:2379
etcdctl --endpoints=$ETCD_ENDPOINTS --write-out=table member list
etcdctl --endpoints=$ETCD_ENDPOINTS --write-out=table endpoint status