使用etcd快照恢复集群数据

备份etcd及相关证书

 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
32
33
#!/bin/bash
set -eux

mkdir -p /cpaas/{etcd_bak,pki_bak}
BACKUP_ETC_DIR=/cpaas/etcd_bak
BACKUP_PKI_DIR=/cpaas/pki_bak/
IP=`/usr/sbin/ifconfig eth0 | grep -w 'inet' | awk '{print $2}'`
ETCDCTL=/usr/local/bin/etcdctl
TAR=/usr/bin/tar

backup_etcd()
{
    ETCDCTL_API=3 ${ETCDCTL} --endpoints ${IP}:2379 \
        --cert="/etc/kubernetes/pki/etcd/server.crt" \
        --key="/etc/kubernetes/pki/etcd/server.key" \
        --cacert="/etc/kubernetes/pki/etcd/ca.crt" \
    snapshot save ${BACKUP_ETC_DIR}/snap-$(date +%Y%m%d%H%M).db
}

backup_pki()
{
    ${TAR} -cvf ${BACKUP_PKI_DIR}pki-$(date +%Y%m%d%H%M).tar /etc/kubernetes/pki/
}

del_backup()
{
    find ${BACKUP_ETC_DIR} -mtime +5 -a -name '*.db' | xargs rm -rf
    find ${BACKUP_PKI_DIR} -mtime +5 -a -name '*.tar' | xargs rm -rf
}

backup_etcd ## 备份etcd
backup_pki ## 备份证书
del_backup ## 删除7天前日志

恢复

***注意:***恢复的顺序是 global 集群 、 业务集群。如果只有业务集群升级失败,不支持只回滚业务集群,必须都要回滚,因为 global 集群上,存有业务集群的 hr 资源。

  1. 获取 etcd 地址,并停掉所有(业务集群和 global 集群) master 节点上的 kubelet 服务。

    • 执行命令的环境: 业务集群和 global 集群的所有 master 节点上

    • 执行的命令:

      1
      2
      3
      4
      5
      6
      7
      
        ETCD_SERVER=($(kubectl get pod -n kube-system $(kubectl get pod -n kube-system | \
        grep etcd | awk 'NR==1 {print $1}') -o yaml | \
        awk '/--initial-cluster=/{print}' | \
        sed -e 's/,/ /g' -e's/^.*cluster=//' | \
        sed -e 's#[0-9\.]*=https://##g' -e 's/:2380//g'))
              
        systemctl stop kubelet
      
  2. 删掉 kube-apiserver 容器,目的是恢复过程和恢复之后,global 不要通过调用 kubeapi 写数据到业务集群的 etcd 内。

    • 执行命令的环境: 要恢复 Kubernetes 集群的所有 master 节点上

    • 执行的命令:

      docker rm -f $(docker ps -a | awk '/_kube-api/{print $NF}')

    • 命令的结果: 所有 kube-api 的容器都被删除。

  3. 判断 etcdctl 命令是否存在第一台 master 节点上,一般执行 backup_recovery.sh 这个备份 etcd 的脚本,会自动将 etcdctl 拷贝到 /usr/bin/etcdctl,如果不存在,需要自行手动拷贝出来。

    • 执行命令的环境: 要恢复 Kubernetes 集群的第一台 master 节点上

    • 执行的命令: whereis etcdctl

    • 命令的结果: 应该打印处 etcdctl 的路径,如果没有就表明是错的。

  4. 通过备份的快照恢复 etcd。

    • 执行命令的环境: 要恢复 Kubernetes 集群的第一台 master 节点上

    • 执行的命令:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      
      mkdir /tmp/dd
      ETCD_SERVER=($(kubectl get pod -n kube-system $(kubectl get pod -n kube-system | grep etcd | awk 'NR==1 {print $1}') -o yaml | awk '/--initial-cluster=/{print}' | sed -e 's/,/ /g' -e's/^.*cluster=//' | sed -e 's#[0-9\.]*=https://##g' -e 's/:2380//g'))  ## 这个地址在回滚的第一步已经获取了,执行回滚之前,echo 这个变量检查地址是否获取成功
      snapshot_db=<备份时,导出的 etcd 快照文件名,必须是绝对路径>
      for i in ${ETCD_SERVER[@]}
      do
          export ETCDCTL_API=3
          etcdctl snapshot restore ${snapshot_db} \
          --cert=/etc/kubernetes/pki/etcd/server.crt \
          --key=/etc/kubernetes/pki/etcd/server.key \
          --cacert=/etc/kubernetes/pki/etcd/ca.crt \
          --data-dir=/tmp/dd/etcd \
          --name ${i} \
          --initial-cluster ${ETCD_SERVER[0]}=https://${ETCD_SERVER[0]}:2380,${ETCD_SERVER[1]}=https://${ETCD_SERVER[1]}:2380,${ETCD_SERVER[2]}=https://${ETCD_SERVER[2]}:2380 \
          --initial-advertise-peer-urls https://$i:2380 && \
      mv /tmp/dd/etcd etcd_$i
      done
      
    • 命令的结果: 会生成 etcd_<ip 地址> 这样的三个目录,将这三个目录拷贝到对应ip的服务器的 /root 内。

  5. 删掉 etcd 容器。

    • 执行命令的环境: 要恢复 Kubernetes 集群的所有 master 节点上

    • 执行的命令: docker rm -f $(docker ps -a | awk '/_etcd/{print $NF}')

    • 命令的结果: 所有 etcd 的容器都被删除。

  6. 迁移恢复的数据。

    • 执行命令的环境: 要恢复 Kubernetes 集群的所有 master 节点上

    • 执行的命令:

      1
      2
      3
      
      docker ps -a | awk '/_etcd/{print $NF}' ##确保没有 etcd 容器
      mv /var/lib/etcd/member /cpaas/backup
      mv /root/var/lib/etcd/member  /var/lib/etcd
      
    • 命令的结果: 会把 etcd 的数据挪到备份目录下,然后将上一步生成的目录拷贝到 /var/lib/etcd 里。

  7. 启动 etcd 和 kube-api。

    • 执行命令的环境: 要恢复 Kubernetes 集群的所有 master 节点上

    • 执行的命令: systemctl start kubelet

    • 命令的结果: kubelet 服务启动后,会自动创建 etcd 的 pod,这个时候执行 docker ps -a | grep -E 'etcd|kube-api' 会找到 etcd 和 kube-api 容器。

  8. 问题解决

    • 回滚之后,如果出现在kubelet和页面查看所有资源都存在,但是在业务节点没有资源的情况,重启k8s 集群内所有节点的 kubelet 和 docker 服务,也可采用重启集群内所有服务器的方式来解决