备份和恢复管理员集群

本文档介绍如何备份和恢复管理员集群的 etcd 存储区。此文档还提供了一个脚本,您可以使用该脚本自动备份集群的 etcd 存储区。

您可以创建备份文件,以便从可能会破坏集群的 etcd 数据的可预见灾难中恢复数据。请将备份文件存储在集群外部且不依赖于集群操作的位置。

限制

  • 此过程不会备份应用特定的数据。

  • 此过程不会备份您的 PersistentVolume。

  • 创建备份后安排的工作负载不会随该备份一起恢复。

  • 升级失败后,您无法恢复集群。

  • 此过程不适用于恢复已删除的集群。

备份管理员集群

管理员集群备份包含以下内容:

  • 管理员集群的 etcd 快照。
  • 管理员控制层面的 Secret,这是向管理员集群和用户集群进行身份验证所必需的。

在创建管理员集群备份前,请完成以下步骤:

  1. 找到管理员集群的外部 IP 地址(用于通过 SSH 连接到管理员集群控制层面):

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] get nodes -n kube-system -o wide | grep master

    其中,[ADMIN_CLUSTER_KUBECONFIG] 是管理员集群的 kubeconfig 文件。

  2. 从管理员集群的私钥创建一个名为 vsphere_tmp 的 SSH 密钥。

    您可以从管理员集群 Secret 中找到私钥:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] get secrets sshkeys -n kube-system -o yaml

    在命令输出中,您可以在 vsphere_tmp 字段中找到私钥。

    将私钥复制到 vsphere_tmp

    echo "[PRIVATE_KEY]" | base64 -d > vsphere_tmp; chmod 600 vsphere_tmp
  3. 检查您能否使用此私钥通过 shell 进入管理员控制层面:

    ssh -i vsphere_tmp ubuntu@[EXTERNAL_IP]
    
  4. 退出该容器:

    exit

备份管理员集群的 etcd 存储区

要备份管理员集群的 etcd 存储区,请执行以下操作:

  1. 获取 etcd pod 的名称:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] get pods \
        -n kube-system -l component=etcd,tier=control-plane -ojsonpath='{$.items[*].metadata.name}{"\n"}'
  2. 通过 shell 进入 pod 的 kube-etcd 容器:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG]  exec -it \
        -n kube-system [ADMIN_ETCD_POD] -- bin/sh

    其中,[ADMIN_ETCD_POD] 是 etcd pod 的名称。

  3. 在 Shell 中,使用 etcdctl 在本地目录中创建一个名为 snapshot.db 的备份:

    ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt \
        --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
        --key=/etc/kubernetes/pki/etcd/healthcheck-client.key snapshot save /tmp/snapshot.db
    
  4. 退出该容器:

    exit
  5. 使用 kubectl cp 从 kube-etcd 容器中复制备份:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] cp \
    kube-system/[ADMIN_ETCD_POD]:tmp/snapshot.db [RELATIVE_DIRECTORY]
    

    其中,[RELATIVE_DIRECTORY] 是存储备份的路径。

备份管理员集群的 Secret

要备份管理员控制层面的 Secret,请执行以下操作:

  1. 使用 SSH 连接到管理员控制层面节点:

    ssh -i vsphere_tmp ubuntu@EXTERNAL_IP
    

    EXTERNAL_IP 替换为您之前记下的管理员控制层面的外部 IP 地址。

  2. 创建本地备份目录是可选步骤,但我们强烈建议您执行。

    您需要更改备份 Secret 的权限,以将其复制到节点之外。

    mkdir backup
  3. 在本地将 Secret 复制到本地备份目录:

    sudo cp -r /etc/kubernetes/pki/* backup/
  4. 更改备份 Secret 的权限:

    sudo chmod -R a+rX backup/
  5. 退出管理员控制层面节点:

    exit
  6. 运行 scp 从管理员控制层面节点复制备份文件夹:

    sudo scp -r -i vsphere_tmp  ubuntu@EXTERNAL_IP:backup/ RELATIVE_DIRECTORY
    

    RELATIVE_DIRECTORY 替换为您要用于存储备份的路径。

恢复管理员集群

以下过程会重新创建备份管理员集群以及创建 etcd 快照时其管理的所有用户控制层面。

  1. 运行 scp 以将 snapshot.db 复制到管理员控制层面:

    sudo scp -i vsphere_tmp snapshot.db ubuntu@[EXTERNAL_IP]:

    其中,[EXTERNAL_IP] 是您之前收集的管理员控制层面的外部 IP 地址。

  2. 通过 shell 进入管理员控制层面:

    sudo ssh -i vsphere_tmp ubuntu@[EXTERNAL_IP]
    
  3. snapshot.db/ 复制到 /mnt

    sudo cp snapshot.db /mnt/
  4. 设置临时目录,例如 backup

    mkdir backup
  5. 退出管理员控制层面:

    exit
  6. 将证书复制到 backup/

    sudo scp -r -i vsphere_tmp [BACKUP_CERT_FILE] ubuntu@[EXTERNAL_IP]:backup/
  7. 通过 shell 进入管理员控制层面节点:

    ssh -i vsphere_tmp ubuntu@[EXTERNAL_IP]
    

    其中,[EXTERNAL_IP] 是您之前收集的管理员控制层面的外部 IP 地址。

  8. 停止 kube-etcdkube-apiserver

    sudo mv /etc/kubernetes/manifests/etcd.yaml /tmp/etcd.yaml
    sudo mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/kube-apiserver.yaml
  9. 将备份 Secret 复制到 /etc/kubernetes/pki/

    sudo cp -r backup/* /etc/kubernetes/pki/
  10. 使用 Docker 运行 etcdctl restore

    sudo docker run --rm \
    -v '/mnt:/backup' \
    -v '/var/lib/etcd:/var/lib/etcd' --env ETCDCTL_API=3 'gcr.io/gke-on-prem-release/etcd-util:GKE_ON_PREM_VERSION' /bin/sh -c "etcdctl snapshot restore '/backup/snapshot.db'; rm -r /var/lib/etcd/*; mv /default.etcd/member/ /var/lib/etcd/"
  11. 重启 kube-etcdkube-apiserver

    sudo mv /tmp/etcd.yaml /etc/kubernetes/manifests/etcd.yaml
    sudo mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml
  12. 验证 kube-etcdkube-apiserver 已启动。

    sudo crictl ps -a
  13. /etc/kubernetes/admin.conf 复制到 .kube 文件夹,以便从管理员工作站访问:

    mkdir -p [HOME]/.kube
    sudo cp -i /etc/kubernetes/admin.conf [HOME]/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
  14. 退出管理员控制层面:

    exit
  15. 从管理员节点复制新生成的 kubeconfig 文件:

    sudo scp -i vsphere_tmp ubuntu@[EXTERNAL_IP]:[HOME]/.kube/config kubeconfig
    sudo chown $(id -u):$(id -g) kubeconfig

    其中:

    • [EXTERNAL_IP] 是管理员控制层面的外部 IP 地址。
    • [HOME] 是管理员节点上的主目录。

    现在,您可以使用这一新的 kubeconfig 文件访问恢复的集群。

排查管理员集群恢复问题

如果您在恢复管理员集群时遇到问题,则必须与 Google 支持团队联系以解决管理员集群相关问题。

在此期间,您可以查看以下各项以进一步进行问题排查。

  1. 查找 etcd 容器 ID

    sudo crictl ps -a | grep [ADMIN_ETCD_POD]

    其中,[ADMIN_ETCD_POD] 是 etcd pod 的名称。

  2. 检查来自 etc 容器

    sudo crictl logs [ETCD_CONTAINER_ID]
    的日志

    其中,[ETCD_CONTAINER_ID] 是 etcd 容器的 ID。

  3. 查找如下权限遭拒的日志消息

    etcdserver: create snapshot directory error:mkdir /var/lib/etcd/member/snap: permission denied

  4. 如果发现权限遭拒的消息,请更新 /opt/data/var/lib/etcd/ 的所有权

    sudo chown -R 2001:2001 /opt/data/var/lib/etcd/

  5. 验证 kube-etcdkube-apiserver 是否已启动。

    sudo crictl ps

自动备份集群

您可以使用此处提供的示例脚本自动备份集群。请注意,以下脚本不受支持,仅供参考,您应在此基础上编写更好、更可靠且更完善的脚本。在运行脚本之前,请在脚本开头填写五个变量的值:

  • BACKUP_DIR 设置为您要存储管理员集群和用户集群备份的路径。此路径不应存在。
  • ADMIN_CLUSTER_KUBECONFIG 设置为管理员集群的 kubeconfig 文件的路径。
  • USER_CLUSTER_NAMESPACE 设置为您的用户集群的名称。用户集群的名称是管理员集群中的命名空间。
  • EXTERNAL_IP 设置为您为管理员控制层面服务预留的 VIP。
  • SSH_PRIVATE_KEY 设置为 SSH 密钥的路径。
  • 如果您使用的是专用网络,请将 JUMP_IP 设置为该网络的跳转服务器的 IP 地址。
#!/usr/bin/env bash
 
# Automates manual steps for taking backups of user and admin clusters.
# Fill in the variables below before running the script.
 
BACKUP_DIR=""                       # path to store user and admin cluster backups
ADMIN_CLUSTER_KUBECONFIG=""         # path to admin cluster kubeconfig
USER_CLUSTER_NAMESPACE=""           # user cluster namespace
EXTERNAL_IP=""                      # admin control plane node external ip - follow steps in documentation
SSH_PRIVATE_KEY=""                  # path to vsphere_tmp ssh private key - follow steps in documentation
JUMP_IP=""                          # network jump server IP - leave empty string if not using private network.
 
mkdir -p $BACKUP_DIR
mkdir $BACKUP_DIR/pki
 
# USER CLUSTER BACKUP
 
# Snapshot user cluster etcd
kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} exec -it -n ${USER_CLUSTER_NAMESPACE} kube-etcd-0 -c kube-etcd -- /bin/sh -ec "export ETCDCTL_API=3; etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etcd.local.config/certificates/etcdCA.crt --cert=/etcd.local.config/certificates/etcd.crt --key=/etcd.local.config/certificates/etcd.key snapshot save /tmp/${USER_CLUSTER_NAMESPACE}_snapshot.db"
kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} cp ${USER_CLUSTER_NAMESPACE}/kube-etcd-0:tmp/${USER_CLUSTER_NAMESPACE}_snapshot.db $BACKUP_DIR/user-cluster_${USER_CLUSTER_NAMESPACE}_snapshot.db 
 
# ADMIN CLUSTER BACKUP
 
# Set up ssh options
SSH_OPTS=(-oStrictHostKeyChecking=no -i ${SSH_PRIVATE_KEY})
if [ "${JUMP_IP}" != "" ]; then
    SSH_OPTS+=(-oProxyCommand="ssh -oStrictHostKeyChecking=no -i ${SSH_PRIVATE_KEY} -W %h:%p ubuntu@${JUMP_IP}")
fi
 
# Copy admin certs
ssh "${SSH_OPTS[@]}" ubuntu@${EXTERNAL_IP} 'sudo chmod -R a+rX /etc/kubernetes/pki/*'
scp -r "${SSH_OPTS[@]}" ubuntu@${EXTERNAL_IP}:/etc/kubernetes/pki/* ${BACKUP_DIR}/pki/
 
# Snapshot admin cluster etcd
admin_etcd=$(kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} get pods -n kube-system -l component=etcd,tier=control-plane -ojsonpath='{$.items[*].metadata.name}{"\n"}')
kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} exec -it -n kube-system ${admin_etcd} -- /bin/sh -ec "export ETCDCTL_API=3; etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key snapshot save /tmp/admin_snapshot.db"
kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} cp -n kube-system ${admin_etcd}:tmp/admin_snapshot.db $BACKUP_DIR/admin-cluster_snapshot.db

后续步骤