备份和恢复用户集群

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

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

限制

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

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

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

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

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

备份用户集群

用户集群备份是用户集群的 etcd 存储区的快照。 etcd 存储区包含管理集群状态所需的所有 Kubernetes 对象和自定义对象。快照包含重新创建集群组件和工作负载所需的数据。

如需创建 etcd 存储区的快照,请执行以下步骤:

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

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG exec -it \
       kube-etcd-0 --container kube-etcd --namespace USER_CLUSTER_NAME \
       -- bin/sh
    

    其中:

    • ADMIN_CLUSTER_KUBECONFIG 是管理员集群的 kubeconfig 文件。
    • USER_CLUSTER_NAME 是用户集群的名称。
  2. 在 shell 的根目录中,创建名为 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 /tmp/snapshot.db
    
  3. 在 shell 中,输入 exit 以退出 shell。

  4. snapshot.dbkube-etcd 容器复制到当前目录:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG cp \
       USER_CLUSTER_NAME/kube-etcd-0:/tmp/snapshot.db \
       --container kube-etcd snapshot.db
    

从备份恢复用户集群(非 HA)

在使用备份文件恢复用户集群的 etcd 存储区之前,请先诊断集群并解决现有问题。使用备份来恢复有问题的集群可能会重新创建或加剧问题。请联系 Anthos Clusters on VMware 支持团队,以获取有关恢复集群的更多帮助。

以下说明介绍了在集群的 etcd 数据已损坏且用户集群的 etcd pod 出现崩溃循环时,如何使用备份文件恢复用户集群。

您可以部署一个实用程序 pod(使用备份覆盖已损坏的数据)来恢复 etcd 数据。管理员集群的 API 服务器必须正在运行,并且管理员集群的调度器必须能够安排新的 pod。

  1. 在用户集群中查找 etcd 使用的 Secret 的名称:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG -n USER_CLUSTER_NAME \
        get secrets | grep kube-etcd-certs
    
  2. 将以下 pod 清单复制到名为 etcd-utility.yaml 的文件中。请替换以下内容:

    • NODE_NAME:运行 kube-etcd-0 pod 的节点。

    • ADMIN_CLUSTER_KUBECONFIG:管理员集群的 kubeconfig 文件。

    • USER_CLUSTER_NAME:用户集群的名称。

    • GKE_ON_PREM_VERSION:要在其中执行 etcd 恢复的集群版本(例如 1.5.0-gke.0)。

    • KUBE_ETCD_SECRET_NAME:用户集群中 etcd 使用的 Secret 的名称,以 kube-etcd-certs 开头。

    apiVersion: v1
    kind: Pod
    metadata:
      name: etcd-utility-0
      namespace: USER_CLUSTER_NAME
    spec:
      containers:
      - command: ["/bin/sh"]
        args: ["-ec", "while :; do echo '.'; sleep 5 ; done"]
        image: gcr.io/gke-on-prem-release/etcd-util:GKE_ON_PREM_VERSION
        name: etcd-utility
        volumeMounts:
        - mountPath: /var/lib/etcd
          name: data
        - mountPath: /etcd.local.config/certificates
          name: etcd-certs
      nodeSelector:
        kubernetes.googleapis.com/cluster-name: USER_CLUSTER_NAME
        kubernetes.io/hostname: NODE_NAME
      tolerations:
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists
        tolerationSeconds: 300
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
        tolerationSeconds: 300
      - effect: NoSchedule
        key: node.kubernetes.io/unschedulable
        operator: Exists
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: data-kube-etcd-0
      - name: etcd-certs
        secret:
          defaultMode: 420
          secretName: KUBE_ETCD_SECRET_NAME
    
  3. 部署实用程序 pod:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG \
       create -f etcd-utility.yaml --namespace USER_CLUSTER_NAME
    
  4. snapshot.db 从当前目录复制到实用程序 pod 的根目录:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG cp snapshot.db \
       USER_CLUSTER_NAME/etcd-utility-0:snapshot.db --container etcd-utility
    
  5. 通过 shell 进入 etcd-utility 容器:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG exec it \
       etcd-utility-0 --container etcd-utility --namespace USER_CLUSTER_NAME \
       -- bin/sh
    
  6. 在 shell 的根目录中,运行以下命令创建一个包含备份的新文件夹:

    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
    
  7. 在 shell 中,删除旧的 etcd 数据:

    rm -r var/lib/etcd/*
    
  8. 在 shell 中,将恢复后的 etcd 数据复制到其永久位置:

    cp -r default.etcd/* var/lib/etcd/
    
  9. 在 shell 中,输入 exit 以退出 shell。

  10. 删除崩溃的 etcd pod:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG \
       delete pod kube-etcd-0 --namespace USER_CLUSTER_NAME
    
  11. 验证 etcd pod 是否不再崩溃。

  12. 删除实用程序 pod:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG \
       delete pod etcd-utility-0 --namespace USER_CLUSTER_NAME
  13. 从当前目录中移除 etcd-utility.yaml

    rm etcd-utility.yaml
    

从备份恢复用户集群 (HA)

本部分介绍如何为高可用性 (HA) 用户集群恢复 etcd 数据。

对于高可用性用户集群,管理员集群中有三个节点作为用户集群的控制层面。这些节点中的每个节点都运行一个 etcd pod,该 pod 维护存储卷上的 etcd 数据。

如果有两个 etcd pod 运行状况良好,并且关联存储卷上的数据保持不变,则无需使用备份文件。这是因为您仍然有一个 etcd 仲裁。

在极少数情况下,如果两个 etcd 存储卷中的数据都损坏,则您需要使用备份文件来恢复 etcd 数据。

要执行本部分中的步骤,您必须已按照备份用户集群中的说明创建了一个 snapshot.db 文件。

列出您的 etcd pod 和节点

  1. 列出管理您的用户集群的 etcd 存储区的 etcd pod。这些 pod 在管理员集群中运行:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG get pods --namespace USER_CLUSTER_NAME \
        --output wide | grep kube-etcd
    

    输出结果会显示 etcd pod 和 pod 运行的节点。输出中显示的节点是管理员集群中作为用户集群控制层面的节点:

    NAME              ...   NODE
    kube-etcd-0       ...   node-xxx
    kube-etcd-1       ...   node-yyy
    kube-etcd-2       ...   node-zzz
    
  2. 记下 Pod 名称和控制层面节点名称以备后续使用。

    请注意,每个 etcd pod 都会以 kube-etcd 后跟数字的形式来命名。 此数字称为 pod 的“成员编号”。它会将 pod 标识为容纳用户集群对象数据的 etcd 集群的特定成员。本指南使用占位符 MEMBER_NUMBER 来指代 etcd pod 成员编号。

    另请注意,etcd 集群中的每个 pod 都在各自的节点上运行。

准备部署实用程序 pod

  1. 为用户集群的 Kubernetes API 服务器保存 PodDisruptionBudget (PDB) 清单。然后删除 PDB。

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG get pdb --namespace USER_CLUSTER_NAME \
       kube-apiserver-pdb --output yaml > kube-apiserver-pdb.yaml
    
    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG delete pdb --namespace USER_CLUSTER_NAME \
       kube-apiserver-pdb
    
  2. 停止 Kubernetes API 服务器和 etcd 维护 Deployment。这样可以确保在恢复期间没有组件使用 etcd:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG --namespace USER_CLUSTER_NAME \
       scale --replicas 0 statefulset kube-apiserver
    
    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG --namespace USER_CLUSTER_NAME \
       scale --replicas 0 deployment gke-master-etcd-maintenance
    
  3. 回调您的 etcd pod 的容器映像的名称。

部署实用程序 pod

  1. 回调 etcd pod 的名称和运行 pod 的节点的名称。

  2. 在当前目录中将以下 pod 清单保存在名为 etcd-utility-MEMBER_NUMBER.yaml 的文件中:

    apiVersion: v1
    kind: Pod
    metadata:
      name: etcd-utility-MEMBER_NUMBER
      namespace: USER_CLUSTER_NAME
    spec:
      containers:
      - command: ["/bin/sh"]
        args: ["-ec", "while :; do echo '.'; sleep 5 ; done"]
        image: gcr.io/gke-on-prem-release/etcd-util:GKE_ON_PREM_VERSION
        name: etcd-utility
        volumeMounts:
        - mountPath: /var/lib/etcd
          name: data
        - mountPath: /etcd.local.config/certificates
          name: etcd-certs
      nodeSelector:
        kubernetes.googleapis.com/cluster-name: USER_CLUSTER_NAME
        kubernetes.io/hostname: NODE_NAME
      tolerations:
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists
        tolerationSeconds: 300
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
        tolerationSeconds: 300
      - effect: NoSchedule
        key: node.kubernetes.io/unschedulable
        operator: Exists
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: data-kube-etcd-MEMBER_NUMBER
      - name: etcd-certs
        secret:
          defaultMode: 420
          secretName: KUBE_ETCD_SECRET_NAME
    

    上面的清单描述了您为了恢复 etcd 数据而临时运行的实用程序 pod。

  3. 在管理员集群中创建实用程序 pod:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG apply -f etcd-utility-MEMBER_NUMBER.yaml
    
  4. 将备份文件 snapshot.db 复制到实用程序 pod 的根目录中:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG cp snapshot.db \
       USER_CLUSTER_NAME/etcd-utility-MEMBER_NUMBER:snapshot.db
    
  5. 通过 shell 进入实用程序 pod 中的 etcd-utility 容器:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG exec -it --namespace USER_CLUSTER_NAME \
       etcd-utility-MEMBER_NUMBER --container etcd-utility -- bin/sh
    
  6. 在 shell 的根目录中,使用 snapshot.db 来恢复 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 \
        --name=kube-etcd-MEMBER_NUMBER \
        --initial-cluster=kube-etcd-0=https://kube-etcd-0.kube-etcd:2380,kube-etcd-1=https://kube-etcd-1.kube-etcd:2380,kube-etcd-2=https://kube-etcd-2.kube-etcd:2380 \
        --initial-cluster-token=etcd-cluster-1 \
        --initial-advertise-peer-urls=https://kube-etcd-MEMBER_NUMBER.kube-etcd:2380 \
        snapshot restore snapshot.db
    

    上述命令将 etcd 数据存储在 /kube-etcd-MEMBER_NUMBER.etcd 目录中。

  7. 在 shell 中,删除旧的 etcd 数据:

    rm -r var/lib/etcd/*
    
  8. 在 shell 中,将恢复后的 etcd 数据复制到其永久位置:

    cp -r kube-etcd-MEMBER_NUMBER.etcd/* var/lib/etcd/
    
  9. 在 shell 中,移除临时 etcd 目录和备份文件:

    rm -R kube-etcd-MEMBER_NUMBER.etcd/
    rm snapshot.db
    
  10. 在 shell 中,输入 exit 以退出 shell。

  11. 删除实用程序 pod:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG delete pod \
        --namespace USER_CLUSTER_NAME etcd-utility-MEMBER_NUMBER
    

重启组件

现在您已部署和删除了实用程序 pod,接下来需要重启一些集群组件。

  1. kube-etcd StatefulSet 中重启 pod:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG rollout restart statefulset \
        --namespace USER_CLUSTER_NAME kube-etcd
    
  2. 为您的用户集群启动 Kubernetes API 服务器:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG scale statefulset --replicas 3 \
       --namespace USER_CLUSTER_NAME kube-apiserver
    
  3. 为您的用户集群启动 etcd 维护 Deployment:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG scale deployment --replicas 1 \
        --namespace=USER_CLUSTER_NAME  gke-master-etcd-maintenance
    
  4. 为 Kubernetes API 服务器恢复 PDB:

    kubectl --kubeconfig ADMIN_CLUSTER_KUBECONIFG apply -f kube-apiserver-pdb.yaml
    

自动备份集群

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

  • 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/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 +rw /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 admin_snapshot.db"
kubectl --kubeconfig=${ADMIN_CLUSTER_KUBECONFIG} cp -n kube-system ${admin_etcd}:admin_snapshot.db $BACKUP_DIR/admin-cluster_snapshot.db

后续步骤