前言:
etcd作为集群的关键组件之一,还是非常有必要进行定期备份的,本例将会就如何更快更好的备份etcd以及应该有哪些策略做一解析。(二进制部署的etcd集群)
备份什么数据和恢复什么数据?
etcd的数据默认会存放在 /var/lib/etcd/member/,我们发现数据所在的目录,会被分为两个文件夹中:
snap: 存放快照数据,etcd防止WAL文件过多而设置的快照,存储etcd数据状态。
那么,别的方式部署的集群也需要备份etcd集群吗?
基本是不需要的,例如,kubeadm部署的集群,只要把相关的一些文件和证书备份好就可以了。Kubeadm的默认安装时,将etcd的存储数据落地到了宿主机的/var/lib/etcd/目录,将此目录下的文件定期备份起来,如果以后etcd的数据出现问题,需要恢复时,直接将文件还原到此目录下,就实现了单节点的etcd数据恢复。
注:如果etcd容器正在启动,是不能覆盖的,这时只需要将/etc/kubernetes/manifests文件夹重命名,数据文件替换后,将/etc/kubernetes/manifests改回来,过一会就会自动将etcd容器重启起来(这个的原理是修改apiserver的配置文件就会自动重启apiserver服务。)
下面我写的这个脚本不仅适合kubernetes集群的etcd备份恢复,也适合于大数据下使用的etcd以及openstack平台的etcd。
备份和原理:
备份的方式:因为我们备份的是etcd集群,集群的每一个节点都是一样的,因此,在一个节点执行快照备份即可,这样我们会得到一个快照文件。恢复方式:
wal: 存放预写式日志,最大的作用是记录了整个数据变化的全部历程。在etcd中,所有数据的修改在提交前,都要先写入到WAL中。
恢复的方式:整个集群停止,然后进行恢复动作。前面得到的快照文件需要在每个一个节点使用,使用前删除原有的数据文件,然后重启etcd服务,在master节点重启etcd和apiserver服务(两个服务有先后顺序,先etcd服务,然后是apiserver服务),在其它节点重启etcd服务。
OK,基本的etcd集群备份原因和方法我想应该是讲清楚了,那么,下面我就以一个三节点的etcd集群备份和恢复为例,通过shell脚本的方式来自动备份和恢复。
三个节点,一主两工作节点,IP地址为:192.168.217.16/17/18 ,此etcd集群使用了证书,因此,查询什么的需要带上证书。
为了方便etcd集群的操作,做一点优化,并对etcd的常用查询做一点示例:
vim /etc/profile
alias etcd_search='ETCDCTL_API=3 /opt/etcd/bin/etcdctl --endpoints=https://192.168.217.16:2379,https://192.168.217.17:2379,https://192.168.217.18:2379 --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem'
激活变量:
sourc /etc/profile
1,etcd集群成员查询
[root@k8s-master ~]# etcd_search member list -w table +------------------+---------+--------+-----------------------------+-----------------------------+ | ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | +------------------+---------+--------+-----------------------------+-----------------------------+ | 1a58a86408898c44 | started | etcd-1 | https://192.168.217.16:2380 | https://192.168.217.16:2379 | | 67146ac2958941d0 | started | etcd-2 | https://192.168.217.17:2380 | https://192.168.217.17:2379 | | e078026890aff6e3 | started | etcd-3 | https://192.168.217.18:2380 | https://192.168.217.18:2379 | +------------------+---------+--------+-----------------------------+-----------------------------+
2,etcd集群检查点健康查询
[root@k8s-master ~]# etcd_search endpoint health -w table https://192.168.217.16:2379 is healthy: successfully committed proposal: took = 3.675613ms https://192.168.217.17:2379 is healthy: successfully committed proposal: took = 4.341192ms https://192.168.217.18:2379 is healthy: successfully committed proposal: took = 5.6451ms
3,etcd集群检查点状态查询
[root@k8s-master ~]# etcd_search endpoint status -w table +-----------------------------+------------------+---------+---------+-----------+-----------+------------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX | +-----------------------------+------------------+---------+---------+-----------+-----------+------------+ | https://192.168.217.16:2379 | 1a58a86408898c44 | 3.3.13 | 20 kB | true | 2 | 17 | | https://192.168.217.17:2379 | 67146ac2958941d0 | 3.3.13 | 20 kB | false | 2 | 17 | | https://192.168.217.18:2379 | e078026890aff6e3 | 3.3.13 | 20 kB | false | 2 | 17 | +-----------------------------+------------------+---------+---------+-----------+-----------+------------+
ETC集群的备份:
在非master节点上新建备份目录(脚本已经写了还是在写一遍):
mkdir -p /opt/etcd_backup_dir/
编写脚本(任意节点都可以,一般还是master上):
vim etcd-bak.sh(注,在master执行的,因此,scp的是其它两个节点地址,要是在17执行,scp那要改一哈的哦)
#!/bin/bash # author zsk_john # date 2022-09-27 set -e #定义了很多变量,按实际情况填写IP相关的变量,备份路径变量也可根据自己喜好定义。 master_ip=192.168.217.16 Slave1_Ip=192.168.217.17 Slave2_Ip=192.168.217.18 BackupDir="/opt/etcd_backup_dir" ETCD_SSL_PATH=/opt/etcd/ssl #这个是证书存放路径,根据实际情况定义 #=================================== ETCD_ENDPOINTS="192.168.217.16:2379" #这个是检查点,根据实际情况定义 CACERT=$ETCD_SSL_PATH/ca.pem #三个etcd用的证书,名称很可能也不一样,有的是ca.crt这样的,实际情况定义 CERT=$ETCD_SSL_PATH/server.pem KEY=$ETCD_SSL_PATH/server-key.pem mkdir -p $BackupDir #建立前面定义的备份文件存放路径,否则脚本失败。 #etctctl这个可执行文件的路径,如果是在系统变量内,留etcdctl就可以 ETCDCTL_API=3 /opt/etcd/bin/etcdctl \ --cacert="${CACERT}" \ --cert="${CERT}" \ --key="${KEY}" \ --endpoints=${ETCD_ENDPOINTS} \ snapshot save $BackupDir/etcd-snapshot-`date +%Y%m%d`.db #按日期命名备份文件,例如,脚本执行后生成的文件名称会是这样的:etcd-snapshot-20220927.db # 备份保留30天 find $BackupDir/ -name *.db -mtime +30 -exec rm -f {} \; scp -r $BackupDir root@$Slave1_Ip:$BackupDir #如果有更多的节点,在上面定义后,将此行复制后修改一哈就可以了,因为是集群,一般都免密,因此,不用担心拷贝不过去。 scp -r $BackupDir root@$Slave2_Ip:$BackupDir echo "`date` etcd cluster is success backup !"
执行脚本即可。该脚本自动将备份文件传到其它两个节点,为以后的备份提供了一点方便。注意一哈,里面写的证书路径不要错了,按实际的来就可以了,因为有的etcd集群会把ca.pem 生成为ca.crt等等。
脚本执行输出如下:
[root@master ~]# bash etcd-bak.sh Snapshot saved at /opt/etcd_backup_dir/etcd-snapshot-20220927.db etcd-snapshot-20220927.db 100% 71MB 25.3MB/s 00:02 etcd-snapshot-20220927.db 100% 71MB 43.6MB/s 00:01 Tue Sep 27 23:06:50 CST 2022 etcd cluster is success backup !
此脚本可反复执行,没有什么bug,主要是变量要定义准确不要错误了。
二,etcd集群恢复
A,cp -rf /var/lib/etcd/default.etcd{,default.etcd.bak}
这里是先备份哈数据文件,以防万一,根据自己实际情况修改此命令
etcd相关配置文件:
#[Member] ETCD_NAME="etcd-1" #这样要复制 ETCD_DATA_DIR="/var/lib/etcd/default.etcd" #这样要复制 ETCD_LISTEN_PEER_URLS="https://192.168.217.16:2380" ETCD_LISTEN_CLIENT_URLS="https://192.168.217.16:2379" #[Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.217.16:2380" #这样要复制 ETCD_ADVERTISE_CLIENT_URLS="https://192.168.217.16:2379" #这样要复制 ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.217.16:2380,etcd-2=https://192.168.217.17:2380,etcd-3=https://192.168.217.18:2380" #这样要复制 ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" #这样要复制 ETCD_INITIAL_CLUSTER_STATE="new"
直接将上面的5个变量复制到下面的脚本,这个脚本在哪个节点,就复制哪个节点上的etcd配置文件的这五个。
vim etc_restore.sh
#!/bin/bash # author zsk_john # date 2022-09-27 set -e rm -rf /var/lib/etcd/default.etcd apiserver_pid=`ps aux |grep apiserver |grep -v grep|wc -l` #判断是否是apiserver,是就停止apiserver,否则不停,只停etcd BackupDir="/opt/etcd_backup_dir" #备份文件路径 BACKUP_FILE="$BackupDir/etcd-snapshot-$1.db" #备份文件名称 ETCD_SSL_PATH=/opt/etcd/ssl #etcd证书存放路径,根据实际填写,结尾不能带/ ETCD_DATA=/var/lib/etcd/default.etcd #etcd数据存放目录,根据实际填写,结尾不能带/ #etcd配置文件里的 ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" #etcd配置文件里的 ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.217.16:2380" #etcd配置文件里的 ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.217.16:2380,etcd-2=https://192.168.217.17:2380,etcd-3=https://192.168.217.18:2380" #etcd配置文件里的 ETCD_NAME=etcd-1 #etcd配置文件里的 if [ $apiserver_pid -eq 1 ]; then echo "this server is master node,will stop apiserver and etcd service" systemctl stop kube-apiserver etcd echo "service apiserver and etcd is Success finished" else echo "this server is not master node,will only stop etcd service" systemctl stop etcd echo "this node's etcd service is success finsihed" fi #停止服务 #================================================================= #cp -rf /var/lib/etcd/default.etcd{,default.etcd.bak} #备份一哈 if [ ! -n "$1" ]; then echo "请输入etcd备份文件的时间" exit fi echo $BACKUP_FILE if [ ! -f "$BACKUP_FILE" ]; then echo "etcd备份文件不存在,请重新执行并输入正确的备份文件时间" exit fi #提醒一哈此脚本是带参的,如果没有输入参数,不执行脚本 #================================================================ ETCDCTL_API=3 /opt/etcd/bin/etcdctl snapshot restore $BACKUP_FILE \ --name "${ETCD_NAME}" \ --initial-cluster="${ETCD_INITIAL_CLUSTER}" \ --initial-advertise-peer-urls=$ETCD_INITIAL_ADVERTISE_PEER_URLS \ --initial-cluster-token=etcd-cluster \ --data-dir=$ETCD_DATA echo "restore etcd is success"
此脚本带参数,参数为备份文件名里的日期,例如:
[root@master ~]# ls -al /opt/etcd_backup_dir/etcd-snapshot-20220927.db -rw-r--r-- 1 root root 74780704 Sep 27 23:09 /opt/etcd_backup_dir/etcd-snapshot-20220927.db
想要恢复27号的etcd,那么执行命令为bash etcd-restore.sh 20220928,如果是28号的etcd,那么就是 bash etcd-restore.sh 20220928:
注意哈:恢复肯定是要整个集群恢复,所以先把脚本复制到其它节点,并且按当前节点的etcd配置文件修改好后,所有节点都执行此恢复脚本。
[root@master ~]# bash etcd-restore.sh 20220927 + rm -rf /var/lib/etcd/default.etcd ++ ps aux ++ grep apiserver ++ grep -v grep ++ wc -l + apiserver_pid=1 + BackupDir=/opt/etcd_backup_dir + BACKUP_FILE=/opt/etcd_backup_dir/etcd-snapshot-20220927.db + ETCD_SSL_PATH=/opt/etcd/ssl + ETCD_DATA=/var/lib/etcd/default.etcd + ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster + ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.217.16:2380 + ETCD_INITIAL_CLUSTER=etcd-1=https://192.168.217.16:2380,etcd-2=https://192.168.217.17:2380,etcd-3=https://192.168.217.18:2380 + ETCD_NAME=etcd-1 + '[' 1 -eq 1 ']' + echo 'this server is master node,will stop apiserver and etcd service' this server is master node,will stop apiserver and etcd service + systemctl stop kube-apiserver etcd + echo 'service apiserver and etcd is Success finished' service apiserver and etcd is Success finished + '[' '!' -n 20220927 ']' + echo /opt/etcd_backup_dir/etcd-snapshot-20220927.db /opt/etcd_backup_dir/etcd-snapshot-20220927.db + '[' '!' -f /opt/etcd_backup_dir/etcd-snapshot-20220927.db ']' + ETCDCTL_API=3 + /opt/etcd/bin/etcdctl snapshot restore /opt/etcd_backup_dir/etcd-snapshot-20220927.db --name etcd-1 --initial-cluster=etcd-1=https://192.168.217.16:2380,etcd-2=https://192.168.217.17:2380,etcd-3=https://192.168.217.18:2380 --initial-advertise-peer-urls=https://192.168.217.16:2380 --initial-cluster-token=etcd-cluster --data-dir=/var/lib/etcd/default.etcd 2022-09-27 23:40:15.248258 I | mvcc: restore compact to 711953 2022-09-27 23:40:15.268601 I | etcdserver/membership: added member 1a58a86408898c44 [https://192.168.217.16:2380] to cluster e4c1916e49e5defc 2022-09-27 23:40:15.268694 I | etcdserver/membership: added member 67146ac2958941d0 [https://192.168.217.17:2380] to cluster e4c1916e49e5defc 2022-09-27 23:40:15.268758 I | etcdserver/membership: added member e078026890aff6e3 [https://192.168.217.18:2380] to cluster e4c1916e49e5defc + echo 'restore etcd is success' restore etcd is success
B,
总结:
etcd恢复还是比较快的,脚本做了一些工作,比如,停服务,因此,恢复完要先启动etcd,然后在其它节点启动etcd,最后启动kube-apiserver服务,顺序不要搞错了哦。
可将备份脚本放入计划任务,实现自动备份哈,这里我就不演示啦,然后恢复的时候根据需要恢复任意天的etcd。
再次强调,集群恢复是所有节点都恢复,不能只恢复一个节点,那样会劈叉的,根据每个节点的etcd配置文件修改脚本。