备份和恢复集群

本页面介绍如何手动创建和恢复 GKE On-Prem 管理员集群和用户集群的 etcd 键值对存储区。此页面还提供了一个脚本,可用于自动备份集群的 etcd 存储区。

您应该创建备份,以便从可能会破坏 etcd 数据和 Secret 的可预见灾难中恢复数据。请务必将备份存储在集群之外的位置,并且该位置不依赖于集群的操作。如果您想要保证安全,也可以考虑创建备份的副本。

虽然每个集群中运行的 etcd 事件 pod 对恢复用户集群并不重要,但您可以按照类似的过程进行备份。另请注意,此过程仅备份 etcd 存储区;本指南不包括备份 PersistentVolume,您应为其规划其他备份和恢复过程。

限制

  • 备份应用专用数据超出了此功能的范围。
  • 在您手动轮替之前,Secret 将一直有效。
  • 创建备份后安排的工作负载不会随该备份一起恢复。
  • 目前,您无法从失败的集群升级中恢复数据。
  • 此过程不适用于恢复已删除的集群。

已知问题

运行 sudo 命令时,您可能会遇到以下错误:

sudo: unable to resolve host gke-admin-master-[CLUSTER_ID]

如果遇到该错误,请将以下行添加到 /etc/hosts 文件中:

127.0.0.1 gke-admin-master-[CLUSTER_ID]

用户集群备份

用户集群备份包含用户集群的 etcd 快照。集群的 etcd 包含所有 Kubernetes 对象以及管理集群状态所需的任何自定义对象等内容。此快照包含重新创建集群组件和工作负载所需的数据。

备份用户集群

用户集群的 etcd 存储在其控制层面节点中,您可以使用管理员集群的 kubeconfig 进行访问。

要创建 etcd 的快照,请执行以下步骤:

  1. 通过 shell 进入 kube-etcd 容器:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] exec \
    -it -n [USER_CLUSTER_NAME] kube-etcd-0 -c \
    kube-etcd -- bin/sh

    其中:

    • [ADMIN_CLUSTER_KUBECONFIG] 是管理员集群的 kubeconfig 文件。
    • [USER_CLUSTER_NAME] 是用户集群的名称。具体来说,您是在管理员集群中传入一个以用户集群命名的命名空间。
  2. 在 shell 中,使用 etcdctl 在本地目录中创建一个名为 snapshot.db 的备份:

    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 snapshot.db
  3. 退出该容器:

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

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] cp \
    [USER_CLUSTER_NAME]/kube-etcd-0:snapshot.db [DIRECTORY] -c kube-etcd

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

恢复用户集群备份

  • 在恢复备份之前,请务必诊断集群并解决现有问题。将备份恢复到有问题的集群可能会重新创建或加剧问题。请联系 GKE On-Prem 支持团队,以获取有关恢复集群的更多帮助。

  • 如果您创建了一个高可用性用户集群,则应为每一个 etcd 集群成员运行一次这些步骤。您可以在恢复每个 etcd 成员时使用相同的快照。除非所有 etcd pod 都崩溃循环,否则请勿执行这些步骤:这表示存在数据损坏。

etcd pod 崩溃循环

以下说明介绍在用户集群的 etcd 数据已损坏且其 etcd pod 出现崩溃循环时如何恢复备份。要进行恢复,您可以将 etcd pod 部署到现有 pod 的卷,然后使用备份覆盖损坏的数据,假设用户集群的 API 服务器正在运行并且可以安排新的 pod。

  1. 在填充以下占位值后,将下面的 etcd pod 规范复制到文件 restore-etcd.yaml 中:

    • [MEMBER_NUMBER] 是您要恢复的已编号的 pod。
    • [NODE_NAME] 是运行 [MEMBER_NUMBER[ pod 的节点。
    • [ADMIN_CLUSTER_KUBECONFIG] 是管理员集群的 kubeconfig 文件。
    • [USER_CLUSTER_NAME] 是用户集群的名称。
    • [DEFAULT_TOKEN] 用于身份验证。您可以通过运行以下命令找到此值:

      kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] \
      -n [USER_CLUSTER_NAME] get pods kube-etcd-0 \
      -o yaml | grep default-token

    restore-etcd.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        Component: restore-etcd-[MEMBER_NUMBER]
      name: restore-etcd-0
      namespace: [USER_CLUSTER_NAME]
    spec:
      restartPolicy: Never
      containers:
      - command: ["/bin/sh"]
        args: ["-ec", "while :; do echo '.'; sleep 5 ; done"]
        image: gcr.io/gke-on-prem-release/etcd:v3.2.24-1-gke.0
        imagePullPolicy: IfNotPresent
        name: restore-etcd
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /var/lib/etcd
          name: data
        - mountPath: /etcd.local.config/certificates
          name: etcd-certs
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: [DEFAULT_TOKEN]
          readOnly: true
      dnsPolicy: ClusterFirst
      hostname: restore-etcd-0
      imagePullSecrets:
      - name: private-registry-creds
      nodeSelector:
        kubernetes.googleapis.com/cluster-name: [USER_CLUSTER_NAME]
        kubernetes.io/hostname: [NODE_NAME]
      priority: 0
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: default
      serviceAccountName: default
      subdomain: restore-etcd
      terminationGracePeriodSeconds: 30
      tolerations:
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists
        tolerationSeconds: 300
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
        tolerationSeconds: 300
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: data-kube-etcd-[MEMBER_NUMBER]
      - name: etcd-certs
        secret:
          defaultMode: 420
          secretName: kube-etcd-certs
      - name: [DEFAULT_TOKEN]
        secret:
          defaultMode: 420
          secretName: [DEFAULT_TOKEN]
          
  2. 部署 pod:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] \
    -n [USER_CLUSTER_NAME] create -f restore-etcd.yaml
  3. 将 etcd 的备份文件 snapshot.db 复制到新的 pod。snapshot.db 位于您创建备份的相对目录中:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] \
    cp [RELATIVE_DIRECTORY]/snapshot.db \
    [USER_CLUSTER_NAME]/restore-etcd-0:snapshot.db
  4. 通过 shell 进入 restore-etcd pod:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] \
    -it -n [USER_CLUSTER_NAME] exec restore-etcd-0 -- bin/sh
  5. 运行以下命令以创建包含备份的新 default.etcd 文件夹:

    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 restore snapshot.db
  6. 使用备份覆盖已损坏的 etcd 数据:

    rm -r var/lib/etcd/*; cp -r default.etcd/* var/lib/etcd/
  7. 退出该容器:

    exit
  8. 删除崩溃的 etcd pod:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] \
    -n [USER_CLUSTER_NAME] delete pod kube-etcd-0
  9. 验证 etcd pod 是否不再崩溃。

  10. 移除 restore-etcd.yaml 并删除 restore-etcd pod:

    rm restore-etcd.yaml;
    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] \
    -n [USER_CLUSTER_NAME] delete pod restore-etcd-0

管理员集群备份

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

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

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

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

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

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

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

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

    kubectl --kubeconfig [ADMIN_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 及其控制层面的 Secret。

etcd

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

  1. 获取 etcd pod 的名称:

    kubectl --kubeconfig [ADMIN_KUBECONFIG] get pods \
    -n kube-system | grep etcd-gke-admin-master
  2. 通过 shell 进入 pod 的 kube-etcd 容器:

    kubectl --kubeconfig [ADMIN_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 snapshot.db
  4. 退出该容器:

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

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

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

Secret

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

  1. 通过 shell 进入管理员控制层面节点:

    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 +rw 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. 运行 kubeadm reset。这将停止仍在管理员集群中运行的任何内容,删除所有 etcd 数据,并删除 /etc/kubernetes/pki/ 中的 Secret:

    sudo kubeadm reset --ignore-preflight-errors=all
  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 'k8s.gcr.io/etcd-amd64:3.1.12' /bin/sh -c "etcdctl snapshot restore '/backup/snapshot.db'; mv /default.etcd/member/ /var/lib/etcd/"
  11. 运行 kubeadm init。这会重复使用所有备份 Secret 并使用已恢复的快照重新启动 etcd:

    sudo kubeadm init --config /etc/kubernetes/kubeadm_config.yaml --ignore-preflight-errors=DirAvailable--var-lib-etcd
  12. 退出管理员控制层面:

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

    sudo scp -i vsphere_tmp ubuntu@[EXTERNAL_IP]:[HOME]/.kube/config kubeconfig

    其中:

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

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

备份脚本

您可以使用此处提供的脚本自动备份集群。在运行脚本之前,请在脚本开头填写五个变量的值:

  • 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 ${USER_CLUSTER_NAMESPACE}_snapshot.db"
kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} cp ${USER_CLUSTER_NAMESPACE}/kube-etcd-0:${USER_CLUSTER_NAMESPACE}_snapshot.db $BACKUP_DIR/

# 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 +rw /etc/kubernetes/pki/*'
scp "${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 -o=name | grep etcd | cut -c 5-)
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 admin_snapshot.db"

问题排查

如需了解详情,请参阅问题排查

使用 gkectl 诊断集群问题

使用 gkectl diagnose 命令识别集群问题并与 Google 共享集群信息。请参阅诊断集群问题

默认日志记录行为

对于 gkectlgkeadm,使用默认日志记录设置便已足够:

  • 默认情况下,日志条目的保存方式如下:

    • 对于 gkectl,默认日志文件为 /home/ubuntu/.config/gke-on-prem/logs/gkectl-$(date).log,该文件与运行 gkectl 的本地目录中的 logs/gkectl-$(date).log 文件进行符号链接。
    • 对于 gkeadm,默认日志文件是运行 gkeadm 的本地目录中的 logs/gkeadm-$(date).log
  • 所有日志条目都会保存在日志文件中,即使它们不输出到终端(当 --alsologtostderrfalse 时)也是如此。
  • -v5 详细程度(默认)涵盖支持团队所需的所有日志条目。
  • 日志文件还包含已执行的命令和失败消息。

我们建议您在需要帮助时将日志文件发送给支持团队。

为日志文件指定非默认位置

要为 gkectl 日志文件指定非默认位置,请使用 --log_file 标志。您指定的日志文件不会与本地目录进行符号链接。

要为 gkeadm 日志文件指定非默认位置,请使用 --log_file 标志。

在管理员集群中查找 Cluster API 日志

如果虚拟机在管理员控制层面启动后无法启动,您可以通过在管理员集群中检查 Cluster API 控制器的日志来尝试进行调试:

  1. kube-system 命名空间中找到 Cluster API 控制器 pod 的名称,其中 [ADMIN_CLUSTER_KUBECONFIG] 是管理员集群的 kubeconfig 文件的路径:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] -n kube-system get pods | grep clusterapi-controllers
  2. 打开 pod 的日志,其中 [POD_NAME] 是 pod 的名称。您可以选择使用 grep 或类似工具来搜索错误:

    kubectl --kubeconfig [ADMIN_CLUSTER_KUBECONFIG] -n kube-system logs [POD_NAME] vsphere-controller-manager

后续步骤