写在最前
服务器只要来一次意外宕机etcd它大概率就会损坏启动不起来,没有备份的你只能提桶跑路了。在此情景我们必须要掌握备份和恢复etcd的技能。
1. 前置环境
为了模拟etcd损坏无法恢复的情况,我们需要准备一个纯净的 k8s 环境。
2. 操作流程
2.1 快速备份
无论是集群还是单机etcd中的内容都是一致彼此同步的,通常会使用定时任务每隔xx小时xx分钟备份一次快照文件。
注意设置 etcd 证书路径,你的证书名称和我的可能会不一样,要检查配置好脚本。
#!/bin/bash
SERVICE_NAME="etcd"
# 检查服务是否在运行
if systemctl is-active --quiet $SERVICE_NAME; then
echo "$SERVICE_NAME is running."
else
echo "$SERVICE_NAME is not running."
exit 1
fi
# 获取当前主机的 IP 地址
CURRENT_IP=$(hostname -I | cut -d' ' -f1)
# 设置备份存储路径
BACKUP_DIR="/root/etcd-backup"
# 设置 etcd 证书路径
CACERT="/etc/ssl/etcd/ssl/ca.pem"
CERT="/etc/ssl/etcd/ssl/admin-master1.pem"
KEY="/etc/ssl/etcd/ssl/admin-master1-key.pem"
# 检查备份目录是否存在,如果不存在则创建
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
fi
# 获取当前时间的年、月、日、小时和分钟
YEAR=$(date +"%Y")
MONTH=$(date +"%m")
DAY=$(date +"%d")
HOUR=$(date +"%H")
MINUTE=$(date +"%M")
# 构建格式化的时间戳
TIMESTAMP="${YEAR}年${MONTH}月${DAY}日${HOUR}时${MINUTE}分"
# 构建备份文件名
BACKUP_FILE="$BACKUP_DIR/etcd_backup_$TIMESTAMP.db"
# 执行 etcd 备份命令
ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints="https://$CURRENT_IP:2379" snapshot save "$BACKUP_FILE" \
--cacert="$CACERT" \
--cert="$CERT" \
--key="$KEY"
if [ $? -eq 0 ]; then
echo "Backup successful: $BACKUP_FILE"
else
echo "Backup failed"
fi
可以看到成功通过脚本备份出etcd的db快照文件了。
2.2 etcd单机还原
我长按笔记本电脑开机按钮几秒强制关机模拟服务器断电宕机,可以看到启动完linux后etcd已经死透了,此操作非常危险如果你没有备份 etcd 那你的环境就死定了。
注意,还原脚本中我写的上来直接删除etcd数据目录,因为实在启动不起来而且我也事先做好备份了。
脚本中的 HOSTNAME 可以在 /etc/hosts 中看到,因为我是单节点k8s所以只有一个,你的环境要按实际内容调整。
#!/bin/bash
#删除之前的,也不备份了!!!
rm -rf /var/lib/etcd
# 获取当前主机的 IP 地址
CURRENT_IP=$(hostname -I | cut -d' ' -f1)
#HOSTNAME=$(hostname)
HOSTNAME="localhost.localdomain.cluster.local"
# 构建自动添加端口的 peer 地址
PEER_URL="https://${CURRENT_IP}:2380"
# 定义 etcd 集群的初始成员信息
INITIAL_CLUSTER="${HOSTNAME}=https://${CURRENT_IP}:2380"
# 定义 etcd 集群的初始成员令牌
INITIAL_CLUSTER_TOKEN="etcd-cluster"
# 设置恢复快照文件
BACKUP_FILE="/root/etcd-backup/etcd_backup_2024年09月19日15时05分.db"
# 设置 etcd 证书路径
CACERT="/etc/ssl/etcd/ssl/ca.pem"
CERT="/etc/ssl/etcd/ssl/admin-node1.pem"
KEY="/etc/ssl/etcd/ssl/admin-node1-key.pem"
ETCDCTL_API=3 etcdctl snapshot restore $BACKUP_FILE \
--name $HOSTNAME \
--cacert "$CACERT" \
--cert "$CERT" \
--key "$KEY" \
--initial-cluster "$INITIAL_CLUSTER" \
--initial-cluster-token etcd-cluster \
--initial-advertise-peer-urls "$PEER_URL" \
--data-dir=/var/lib/etcd
if [ $? -eq 0 ]; then
echo "reset successful"
else
echo "reset failed"
fi
可以看到成功通过脚本还原并顺利启动etcd了。
2.3 etcd集群还原
在恢复 etcd 集群时直接写死固定节点的 IP 地址和名称是一种快速且直接的方法,尤其是当你对集群的配置非常熟悉,我嘛就直接这样写了。
#!/bin/bash
#删除之前的,也不备份了!!!
rm -rf /var/lib/etcd
# 获取当前主机的 IP 地址
CURRENT_IP="172.31.0.31"
HOSTNAME="node1"
# 构建自动添加端口的 peer 地址
PEER_URL="https://172.31.0.31:2380"
# 定义 etcd 集群的初始成员信息
INITIAL_CLUSTER="node1=https://172.31.0.31:2380,node2=https://172.31.0.32:2380,node3=https://172.31.0.33:2380"
# 定义 etcd 集群的初始成员令牌
INITIAL_CLUSTER_TOKEN="etcd-cluster"
# 设置备份存储路径
BACKUP_FILE="/root/etcd-backup/etcd_backup_2024年09月19日15时05分.db"
# 设置 etcd 证书路径
CACERT="/etc/ssl/etcd/ssl/ca.pem"
CERT="/etc/ssl/etcd/ssl/admin-node1.pem"
KEY="/etc/ssl/etcd/ssl/admin-node1-key.pem"
ETCDCTL_API=3 etcdctl snapshot restore $BACKUP_FILE \
--name $HOSTNAME \
--cacert "$CACERT" \
--cert "$CERT" \
--key "$KEY" \
--initial-cluster "$INITIAL_CLUSTER" \
--initial-cluster-token etcd-cluster \
--initial-advertise-peer-urls "$PEER_URL" \
--data-dir=/var/lib/etcd
if [ $? -eq 0 ]; then
echo "reset successful"
else
echo "reset failed"
fi
3. 异常解决
3.1 connect: no route to host
[root@localhost shell]# kubectl logs -n kubesphere-system ks-controller-manager-5fbf7f9b9f-8vht4
W0919 16:30:58.374922 1 client_config.go:615] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
I0919 16:30:58.376103 1 server.go:202] setting up manager
E0919 16:30:59.378441 1 deleg.go:144] "msg"="Failed to get API Group-Resources" "error"="Get \"https://10.233.0.1:443/api?timeout=32s\": dial tcp 10.233.0.1:443: connect: no route to host"
F0919 16:30:59.378480 1 server.go:207] unable to set up overall controller manager: Get "https://10.233.0.1:443/api?timeout=32s": dial tcp 10.233.0.1:443: connect: no route to host
出现这个奇怪的ip,我们可以通过ip a
命令查找网卡,可以看到这个虚拟ip网段是k8s生成的。
此情况我们可以通过清空防火墙来让kubelet重新添加刷新,执行完稍等一会就能恢复正常了。
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
#超谨慎使用
iptables -F
4. 操作总结
脚本的值还是有点抽象的,具体轮到你如果操作失败可以留言我帮你看看。