5.3. 灾难恢复
5.3.1. 关于灾难恢复 复制链接链接已复制到粘贴板!
灾难恢复文档为管理员提供了如何从 OpenShift Container Platform 集群可能出现的几个灾难情形中恢复的信息。作为管理员,您可能需要遵循以下一个或多个步骤将集群恢复为工作状态。
灾难恢复要求您至少有一个健康的 control plane 主机。
- 恢复到一个以前的集群状态
如果您希望将集群恢复到一个以前的状态时(例如,管理员错误地删除了一些关键信息),则可以使用这个解决方案。这包括您丢失了大多数 control plane 主机并导致 etcd 仲裁丢失,且集群离线的情况。只要您执行了 etcd 备份,就可以按照这个步骤将集群恢复到之前的状态。
如果适用,可能还需要从过期的 control plane 证书中恢复。
警告在一个正在运行的集群中恢复到以前的集群状态是破坏性的,而不稳定的操作。这仅应作为最后的手段使用。
在执行恢复前,请参阅关于恢复集群状态以了解有关对集群的影响的更多信息。
注意如果大多数 master 仍可用,且仍有 etcd 仲裁,请按照以下步骤替换一个不健康的 etcd 成员。
- 从 control plane 证书已过期的情况下恢复
- 如果 control plane 证书已经过期,则可以使用这个解决方案。例如:在第一次证书轮转前(在安装后 24 小时内)关闭了集群,您的证书将不会被轮转,且会过期。可以按照以下步骤从已过期的 control plane 证书中恢复。
5.3.2. 恢复到一个以前的集群状态 复制链接链接已复制到粘贴板!
要将集群恢复到以前的状态,您必须已通过创建快照来备份 etcd 数据。您将需要使用此快照来还原集群状态。如需更多信息,请参阅"恢复 etcd 数据"。
5.3.2.1. 关于恢复集群状态 复制链接链接已复制到粘贴板!
您可以使用 etcd 备份将集群恢复到以前的状态。在以下情况中可以使用这个方法进行恢复:
- 集群丢失了大多数 control plane 主机(仲裁丢失)。
- 管理员删除了一些关键内容,必须恢复才能恢复集群。
在一个正在运行的集群中恢复到以前的集群状态是破坏性的,而不稳定的操作。这仅应作为最后的手段使用。
如果您可以使用 Kubernetes API 服务器检索数据,则代表 etcd 可用,且您不应该使用 etcd 备份来恢复。
恢复 etcd 实际相当于把集群返回到以前的一个状态,所有客户端都会遇到一个有冲突的、并行历史记录。这会影响 kubelet、Kubernetes 控制器管理器、持久性卷控制器和 OpenShift operator 等监视组件的行为,包括网络操作器。
当 etcd 中的内容与磁盘上的实际内容不匹配时,可能会导致 Operator churn,从而导致 Kubernetes API 服务器、Kubernetes 控制器管理器、Kubernetes 调度程序和 etcd 的 Operator 在磁盘上的文件与 etcd 中的内容冲突时卡住。这可能需要手动操作来解决问题。
在极端情况下,集群可能会丢失持久性卷跟踪,删除已不存在的关键工作负载,重新镜像机器,以及重写带有过期证书的 CA 捆绑包。
5.3.2.2. 恢复到一个以前的集群状态 复制链接链接已复制到粘贴板!
您可以使用保存的 etcd 备份来恢复以前的集群状态,或恢复丢失了大多数 control plane 主机的集群。
如果您的集群使用 control plane 机器集,请参阅"为 etcd 恢复 control plane 机器集"中的"恢复降级的 etcd Operator"。
恢复集群时,必须使用同一 z-stream 发行版本中获取的 etcd 备份。例如,OpenShift Container Platform 4.7.2 集群必须使用从 4.7.2 开始的 etcd 备份。
先决条件
-
通过一个基于证书的
kubeconfig使用具有cluster-admin角色的用户访问集群,如安装期间的情况。 - 用作恢复主机的健康 control plane 主机。
- SSH 对 control plane 主机的访问。
-
包含从同一备份中获取的 etcd 快照和静态
pod资源的备份目录。该目录中的文件名必须采用以下格式:snapshot_<datetimestamp>.db和static_kuberesources_<datetimestamp>.tar.gz。 - 节点必须能够访问或可引导。
对于非恢复 control plane 节点,不需要建立 SSH 连接或停止静态 pod。您可以逐个删除并重新创建其他非恢复 control plane 机器。
流程
- 选择一个要用作恢复主机的 control plane 主机。这是您要在其中运行恢复操作的主机。
建立到每个 control plane 节点(包括恢复主机)的 SSH 连接。使用一个单独的终端为每个 control plane 节点建立 SSH 连接。
在恢复过程启动后,Kubernetes API 服务器将无法访问,因此您无法通过
oc debug访问 control plane 节点。因此,需要在一个单独的终端中建立到每个control plane 主机的 SSH 连接。重要如果没有完成这个步骤,将无法访问 control plane 主机来完成恢复过程,您将无法从这个状态恢复集群。
将
etcd备份目录复制到恢复 control plane 主机上。此流程假设您将
backup目录(其中包含etcd快照和静态 pod 资源)复制到恢复 control plane 主机的/home/core/目录中。在任何其他 control plane 节点上停止静态 pod。
注意您不需要停止恢复主机上的静态 pod。
- 访问不是恢复主机的 control plane 主机。
运行以下命令,将现有 etcd pod 文件从 kubelet 清单目录中移出:
$ sudo mv -v /etc/kubernetes/manifests/etcd-pod.yaml /tmp运行以下命令验证
etcdpod 是否已停止:$ sudo crictl ps | grep etcd | egrep -v "operator|etcd-guard"如果这个命令的输出不为空,请等待几分钟,然后再次检查。
运行以下命令,将现有
kube-apiserver文件从 kubelet 清单目录中移出:$ sudo mv -v /etc/kubernetes/manifests/kube-apiserver-pod.yaml /tmp运行以下命令验证
kube-apiserver容器是否已停止:$ sudo crictl ps | grep kube-apiserver | egrep -v "operator|guard"如果这个命令的输出不为空,请等待几分钟,然后再次检查。
运行以下命令,将现有
kube-controller-manager文件从 kubelet 清单目录中移出:$ sudo mv -v /etc/kubernetes/manifests/kube-controller-manager-pod.yaml /tmp运行以下命令验证
kube-controller-manager容器是否已停止:$ sudo crictl ps | grep kube-controller-manager | egrep -v "operator|guard"如果这个命令的输出不为空,请等待几分钟,然后再次检查。
运行以下命令,将现有
kube-scheduler文件从 kubelet 清单目录中移出:$ sudo mv -v /etc/kubernetes/manifests/kube-scheduler-pod.yaml /tmp运行以下命令验证
kube-scheduler容器是否已停止:$ sudo crictl ps | grep kube-scheduler | egrep -v "operator|guard"如果这个命令的输出不为空,请等待几分钟,然后再次检查。
使用以下示例将
etcd数据目录移到不同的位置:$ sudo mv -v /var/lib/etcd/ /tmp如果存在
/etc/kubernetes/manifests/keepalived.yaml文件,请完成以下步骤。这些步骤是确保 API IP 地址侦听恢复主机所必需的。运行以下命令,将
/etc/kubernetes/manifests/keepalived.yaml文件从 kubelet 清单目录中移出:$ sudo mv -v /etc/kubernetes/manifests/keepalived.yaml /home/core/注意在流程完成后,该文件必须恢复到其原始位置。
容器验证由
keepalived守护进程管理的任何容器是否已停止:$ sudo crictl ps --name keepalived命令输出应该为空。如果它不是空的,请等待几分钟后再重新检查。
检查 control plane 是否已分配任何 Virtual IP (VIP):
$ ip -o address | egrep '<api_vip>|<ingress_vip>'对于每个报告的 VIP,运行以下命令将其删除:
$ sudo ip address del <reported_vip> dev <reported_vip_device>
- 在其他不是恢复主机的 control plane 主机上重复此步骤。
- 访问恢复 control plane 主机。
如果使用
keepalived守护进程,请验证恢复 control plane 节点是否拥有 VIP。否则,重复步骤 4.xi。$ ip -o address | grep <api_vip>如果存在 VIP 的地址(如果存在)。如果 VIP 没有设置或配置不正确,这个命令会返回一个空字符串。
如果启用了集群范围的代理,请确定已导出了
NO_PROXY、HTTP_PROXY和HTTPS_PROXY环境变量。提示您可以通过查看
oc get proxy cluster -o yaml的输出来检查代理是否已启用。如果httpProxy、httpsProxy和noProxy字段设置了值,则会启用代理。在恢复 control plane 主机上运行恢复脚本,并传递到
etcd备份目录的路径:$ sudo -E /usr/local/bin/cluster-restore.sh /home/core/assets/backup脚本输出示例
...stopping kube-scheduler-pod.yaml ...stopping kube-controller-manager-pod.yaml ...stopping etcd-pod.yaml ...stopping kube-apiserver-pod.yaml Waiting for container etcd to stop .complete Waiting for container etcdctl to stop .............................complete Waiting for container etcd-metrics to stop complete Waiting for container kube-controller-manager to stop complete Waiting for container kube-apiserver to stop ..........................................................................................complete Waiting for container kube-scheduler to stop complete Moving etcd data-dir /var/lib/etcd/member to /var/lib/etcd-backup starting restore-etcd static pod starting kube-apiserver-pod.yaml static-pod-resources/kube-apiserver-pod-7/kube-apiserver-pod.yaml starting kube-controller-manager-pod.yaml static-pod-resources/kube-controller-manager-pod-7/kube-controller-manager-pod.yaml starting kube-scheduler-pod.yaml static-pod-resources/kube-scheduler-pod-8/kube-scheduler-pod.yamlcluster-restore.sh 脚本必须显示
etcd、kube-apiserver、kube-controller-manager和kube-schedulerpod 已停止,然后在恢复过程结束时启动。注意如果在上次
etcd备份后更新了节点,则恢复过程可能会导致节点进入NotReady状态。检查节点以确保它们处于
Ready状态。要检查节点,您可以使用堡垒主机或恢复主机。如果使用恢复主机,请运行以下命令:
$ export KUBECONFIG=/etc/kubernetes/static-pod-resources/kube-apiserver-certs/secrets/node-kubeconfigs/localhost-recovery.kubeconfig$ oc get nodes -w如果使用堡垒主机,请完成以下步骤:
运行以下命令:
$ oc get nodes -w输出示例
NAME STATUS ROLES AGE VERSION host-172-25-75-28 Ready master 3d20h v1.30.3 host-172-25-75-38 Ready infra,worker 3d20h v1.30.3 host-172-25-75-40 Ready master 3d20h v1.30.3 host-172-25-75-65 Ready master 3d20h v1.30.3 host-172-25-75-74 Ready infra,worker 3d20h v1.30.3 host-172-25-75-79 Ready worker 3d20h v1.30.3 host-172-25-75-86 Ready worker 3d20h v1.30.3 host-172-25-75-98 Ready infra,worker 3d20h v1.30.3所有节点都可能需要几分钟时间报告其状态。
如果有任何节点处于
NotReady状态,登录到节点,并从每个节点上的/var/lib/kubelet/pki目录中删除所有 PEM 文件。您可以 SSH 到节点,或使用 web 控制台中的终端窗口。$ ssh -i <ssh-key-path> core@<master-hostname>pki目录示例sh-4.4# pwd /var/lib/kubelet/pki sh-4.4# ls kubelet-client-2022-04-28-11-24-09.pem kubelet-server-2022-04-28-11-24-15.pem kubelet-client-current.pem kubelet-server-current.pem
在所有 control plane 主机上重启 kubelet 服务。
在恢复主机中运行以下命令:
$ sudo systemctl restart kubelet.service- 在所有其他 control plane 主机上重复此步骤。
批准待处理的证书签名请求 (CSR):
注意没有 worker 节点的集群(如单节点集群或由三个可调度的 control plane 节点组成的集群)不会批准任何待处理的 CSR。您可以跳过此步骤中列出的所有命令。
运行以下命令,获取当前 CSR 列表:
$ oc get csr输出示例
NAME AGE SIGNERNAME REQUESTOR CONDITION csr-2s94x 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending1 csr-4bd6t 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending2 csr-4hl85 13m kubernetes.io/kube-apiserver-client-kubelet system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending3 csr-zhhhp 3m8s kubernetes.io/kube-apiserver-client-kubelet system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending4 ...运行以下命令,查看 CSR 的详情,以验证其是否有效:
$ oc describe csr <csr_name>1 - 1
<csr_name>是当前 CSR 列表中 CSR 的名称。
运行以下命令来批准每个有效的
node-bootstrapperCSR:$ oc adm certificate approve <csr_name>对于用户置备的安装,请运行以下命令批准每个有效的 kubelet 服务 CSR:
$ oc adm certificate approve <csr_name>
确认单个成员 control plane 已被成功启动。
在恢复主机上,输入以下命令验证
etcd容器是否正在运行:$ sudo crictl ps | grep etcd | egrep -v "operator|etcd-guard"输出示例
3ad41b7908e32 36f86e2eeaaffe662df0d21041eb22b8198e0e58abeeae8c743c3e6e977e8009 About a minute ago Running etcd 0 7c05f8af362f0在恢复主机上,输入以下命令验证
etcdpod 是否正在运行:$ oc -n openshift-etcd get pods -l k8s-app=etcd输出示例
NAME READY STATUS RESTARTS AGE etcd-ip-10-0-143-125.ec2.internal 1/1 Running 1 2m47s如果状态是
Pending,或者输出中列出了多个正在运行的etcdpod,请等待几分钟,然后再次检查。
如果使用
OVNKubernetes网络插件,您必须重启ovnkube-controlplanepod。运行以下命令删除所有
ovnkube-controlplanepod:$ oc -n openshift-ovn-kubernetes delete pod -l app=ovnkube-control-plane运行以下命令,验证所有
ovnkube-controlplanepod 是否已重新部署:$ oc -n openshift-ovn-kubernetes get pod -l app=ovnkube-control-plane
如果使用 OVN-Kubernetes 网络插件,请逐个重启所有节点上的 Open Virtual Network (OVN) Kubernetes pod。使用以下步骤重启每个节点上的 OVN-Kubernetes pod:
重要按照以下顺序重启 OVN-Kubernetes pod
- 恢复控制平面主机
- 其他控制平面主机(如果可用)
- 其他节点
注意验证和变异准入 Webhook 可能会拒绝 pod。如果您添加了额外的 Webhook,其
failurePolicy被设置为Fail的,则它们可能会拒绝 pod,恢复过程可能会失败。您可以通过在恢复集群状态时保存和删除 Webhook 来避免这种情况。成功恢复集群状态后,您可以再次启用 Webhook。另外,您可以在恢复集群状态时临时将
failurePolicy设置为Ignore。成功恢复集群状态后,您可以将failurePolicy设置为Fail。删除北向数据库 (nbdb) 和南向数据库 (sbdb)。使用 Secure Shell (SSH) 访问恢复主机和剩余的 control plane 节点,再运行以下命令:
$ sudo rm -f /var/lib/ovn-ic/etc/*.db重新启动 OpenVSwitch 服务。使用 Secure Shell (SSH) 访问节点,并运行以下命令:
$ sudo systemctl restart ovs-vswitchd ovsdb-server运行以下命令删除节点上的
ovnkube-nodepod,将<node>替换为您要重启的节点的名称:$ oc -n openshift-ovn-kubernetes delete pod -l app=ovnkube-node --field-selector=spec.nodeName==<node>运行以下命令,检查 OVN pod 的状态:
$ oc get po -n openshift-ovn-kubernetes如果有任何 OVN pod 处于
Terminating状态,请运行以下命令来删除运行该 OVN pod 的节点。将<node>替换为您要删除的节点的名称:$ oc delete node <node>运行以下命令,使用 SSH 登录到带有
Terminating状态的 OVN pod 节点:$ ssh -i <ssh-key-path> core@<node>运行以下命令,从
/var/lib/kubelet/pki目录中移动所有 PEM 文件:$ sudo mv /var/lib/kubelet/pki/* /tmp运行以下命令来重启 kubelet 服务:
$ sudo systemctl restart kubelet.service运行以下命令返回恢复 etcd 机器:
$ oc get csr输出示例
NAME AGE SIGNERNAME REQUESTOR CONDITION csr-<uuid> 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending运行以下命令来批准所有新的 CSR,将
csr-<uuid>替换为 CSR 的名称:oc adm certificate approve csr-<uuid>运行以下命令验证节点是否已返回:
$ oc get nodes
使用以下命令验证
ovnkube-nodepod 已再次运行:$ oc -n openshift-ovn-kubernetes get pod -l app=ovnkube-node --field-selector=spec.nodeName==<node>注意pod 可能需要几分钟时间来重启。
逐个删除并重新创建其他非恢复 control plane 机器。重新创建机器后,会强制一个新修订版本,
etcd会自动扩展。如果使用用户置备的裸机安装,您可以使用最初创建它时使用的相同方法重新创建 control plane 机器。如需更多信息,请参阅"在裸机上安装用户置备的集群"。
警告不要为恢复主机删除并重新创建机器。
如果您正在运行安装程序置备的基础架构,或者您使用 Machine API 创建机器,请按照以下步骤执行:
警告不要为恢复主机删除并重新创建机器。
对于安装程序置备的基础架构上的裸机安装,不会重新创建 control plane 机器。如需更多信息,请参阅"替换裸机控制平面节点"。
为丢失的 control plane 主机之一获取机器。
在一个终端中使用 cluster-admin 用户连接到集群,运行以下命令:
$ oc get machines -n openshift-machine-api -o wide输出示例
NAME PHASE TYPE REGION ZONE AGE NODE PROVIDERID STATE clustername-8qw5l-master-0 Running m4.xlarge us-east-1 us-east-1a 3h37m ip-10-0-131-183.ec2.internal aws:///us-east-1a/i-0ec2782f8287dfb7e stopped1 clustername-8qw5l-master-1 Running m4.xlarge us-east-1 us-east-1b 3h37m ip-10-0-143-125.ec2.internal aws:///us-east-1b/i-096c349b700a19631 running clustername-8qw5l-master-2 Running m4.xlarge us-east-1 us-east-1c 3h37m ip-10-0-154-194.ec2.internal aws:///us-east-1c/i-02626f1dba9ed5bba running clustername-8qw5l-worker-us-east-1a-wbtgd Running m4.large us-east-1 us-east-1a 3h28m ip-10-0-129-226.ec2.internal aws:///us-east-1a/i-010ef6279b4662ced running clustername-8qw5l-worker-us-east-1b-lrdxb Running m4.large us-east-1 us-east-1b 3h28m ip-10-0-144-248.ec2.internal aws:///us-east-1b/i-0cb45ac45a166173b running clustername-8qw5l-worker-us-east-1c-pkg26 Running m4.large us-east-1 us-east-1c 3h28m ip-10-0-170-181.ec2.internal aws:///us-east-1c/i-06861c00007751b0a running- 1
- 这是用于丢失的 control plane 主机
ip-10-0-131-183.ec2.internal的 control plane 机器。
运行以下命令,删除丢失的 control plane 主机的机器:
$ oc delete machine -n openshift-machine-api clustername-8qw5l-master-01 - 1
- 为丢失的 control plane 主机指定 control plane 机器的名称。
删除丢失的 control plane 主机的机器后,会自动置备新机器。
运行以下命令验证新机器是否已创建:
$ oc get machines -n openshift-machine-api -o wide输出示例
NAME PHASE TYPE REGION ZONE AGE NODE PROVIDERID STATE clustername-8qw5l-master-1 Running m4.xlarge us-east-1 us-east-1b 3h37m ip-10-0-143-125.ec2.internal aws:///us-east-1b/i-096c349b700a19631 running clustername-8qw5l-master-2 Running m4.xlarge us-east-1 us-east-1c 3h37m ip-10-0-154-194.ec2.internal aws:///us-east-1c/i-02626f1dba9ed5bba running clustername-8qw5l-master-3 Provisioning m4.xlarge us-east-1 us-east-1a 85s ip-10-0-173-171.ec2.internal aws:///us-east-1a/i-015b0888fe17bc2c8 running1 clustername-8qw5l-worker-us-east-1a-wbtgd Running m4.large us-east-1 us-east-1a 3h28m ip-10-0-129-226.ec2.internal aws:///us-east-1a/i-010ef6279b4662ced running clustername-8qw5l-worker-us-east-1b-lrdxb Running m4.large us-east-1 us-east-1b 3h28m ip-10-0-144-248.ec2.internal aws:///us-east-1b/i-0cb45ac45a166173b running clustername-8qw5l-worker-us-east-1c-pkg26 Running m4.large us-east-1 us-east-1c 3h28m ip-10-0-170-181.ec2.internal aws:///us-east-1c/i-06861c00007751b0a running- 1
- 新机器
clustername-8qw5l-master-3会被创建,并在阶段从Provisioning变为Running后就绪。
创建新机器可能需要几分钟时间。当机器或节点返回到健康状态时,
etcd集群 Operator 将自动同步。- 对不是恢复主机的每个已丢失的 control plane 主机重复此步骤。
运行以下命令关闭仲裁保护:
$ oc patch etcd/cluster --type=merge -p '{"spec": {"unsupportedConfigOverrides": {"useUnsupportedUnsafeNonHANonProductionUnstableEtcd": true}}}'此命令可确保您可以成功重新创建机密并推出静态 pod。
如果还没有定义,在恢复主机的一个单独的终端窗口中,运行以下命令来导出恢复
kubeconfig文件:$ export KUBECONFIG=/etc/kubernetes/static-pod-resources/kube-apiserver-certs/secrets/node-kubeconfigs/localhost-recovery.kubeconfig强制
etcd重新部署。在导出恢复
kubeconfig文件的同一终端窗口中,运行以下命令:$ oc patch etcd cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge1 - 1
forceRedeploymentReason值必须是唯一的,这就是为什么附加时间戳的原因。
etcd重新部署开始。当
etcd集群 Operator 执行重新部署时,现有节点开始使用与初始 bootstrap 扩展类似的新 pod。运行以下命令重新打开仲裁保护:
$ oc patch etcd/cluster --type=merge -p '{"spec": {"unsupportedConfigOverrides": null}}'您可以运行以下命令来验证
unsupportedConfigOverrides部分是否已从对象中删除:$ oc get etcd/cluster -oyaml验证所有节点是否已更新至最新的修订版本。
在一个终端中使用
cluster-admin用户连接到集群,运行以下命令:$ oc get etcd -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'查看
etcd的NodeInstallerProgressing状态条件,以验证所有节点是否处于最新的修订版本。在更新成功后,输出会显示AllNodesAtLatestRevision:AllNodesAtLatestRevision 3 nodes are at revision 71 - 1
- 在本例中,最新的修订版本号是
7。
如果输出包含多个修订号,如
2 个节点为修订版本 6;1 个节点为修订版本 7,这意味着更新仍在进行中。等待几分钟后重试。重新部署
etcd后,为 control plane 强制进行新的推出部署。kube-apiserver将在其他节点上重新安装自己,因为 kubelet 使用内部负载均衡器连接到 API 服务器。在一个终端中使用
cluster-admin用户连接到集群,请完成以下步骤:为
kube-apiserver强制进行新的推出部署:$ oc patch kubeapiserver cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge验证所有节点是否已更新至最新的修订版本。
$ oc get kubeapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'查看
NodeInstallerProgressing状态条件,以验证所有节点是否处于最新版本。在更新成功后,输出会显示AllNodesAtLatestRevision:AllNodesAtLatestRevision 3 nodes are at revision 71 - 1
- 在本例中,最新的修订版本号是
7。
如果输出包含多个修订号,如
2 个节点为修订版本 6;1 个节点为修订版本 7,这意味着更新仍在进行中。等待几分钟后重试。运行以下命令,为 Kubernetes 控制器管理器强制进行新的推出部署:
$ oc patch kubecontrollermanager cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge运行以下命令,验证所有节点是否已更新至最新的修订版本:
$ oc get kubecontrollermanager -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'查看
NodeInstallerProgressing状态条件,以验证所有节点是否处于最新版本。在更新成功后,输出会显示AllNodesAtLatestRevision:AllNodesAtLatestRevision 3 nodes are at revision 71 - 1
- 在本例中,最新的修订版本号是
7。
如果输出包含多个修订号,如
2 个节点为修订版本 6;1 个节点为修订版本 7,这意味着更新仍在进行中。等待几分钟后重试。运行以下命令,为
kube-scheduler强制新的推出部署:$ oc patch kubescheduler cluster -p='{"spec": {"forceRedeploymentReason": "recovery-'"$( date --rfc-3339=ns )"'"}}' --type=merge运行以下命令,验证所有节点是否已更新至最新的修订版本:
$ oc get kubescheduler -o=jsonpath='{range .items[0].status.conditions[?(@.type=="NodeInstallerProgressing")]}{.reason}{"\n"}{.message}{"\n"}'查看
NodeInstallerProgressing状态条件,以验证所有节点是否处于最新版本。在更新成功后,输出会显示AllNodesAtLatestRevision:AllNodesAtLatestRevision 3 nodes are at revision 71 - 1
- 在本例中,最新的修订版本号是
7。
如果输出包含多个修订号,如
2 个节点为修订版本 6;1 个节点为修订版本 7,这意味着更新仍在进行中。等待几分钟后重试。
运行以下命令来监控平台 Operator:
$ oc adm wait-for-stable-cluster这个过程最多可能需要 15 分钟。
为确保所有工作负载在恢复过程后返回到正常操作,请重启所有 control plane 节点。
注意完成前面的流程步骤后,您可能需要等待几分钟,让所有服务返回到恢复的状态。例如,在重启 OAuth 服务器 pod 前,使用
oc login进行身份验证可能无法立即正常工作。考虑使用
system:adminkubeconfig文件立即进行身份验证。这个方法基于 SSL/TLS 客户端证书作为 OAuth 令牌的身份验证。您可以发出以下命令来使用此文件进行身份验证:$ export KUBECONFIG=<installation_directory>/auth/kubeconfig发出以下命令以显示您的验证的用户名:
$ oc whoami- 以滚动方式重启所有 worker 节点。
5.3.2.3. 从 etcd 备份手动恢复集群 复制链接链接已复制到粘贴板!
恢复过程在 "Restoring to a previous cluster state" 部分中介绍:
-
需要 2 个 control plane 节点的完整重新创建,这可能是使用 UPI 安装方法安装的集群的一个复杂步骤,因为 UPI 安装不会为 control plane 节点创建任何
Machine或ControlPlaneMachineset。 - 使用脚本 /usr/local/bin/cluster-restore.sh,它会启动新的单成员 etcd 集群,然后将其扩展到三个成员。
相反,这个过程:
- 不需要重新创建任何 control plane 节点。
- 直接启动一个三成员 etcd 集群。
如果集群使用 MachineSet 用于 control plane,建议使用 "Restoring to a previous cluster state" 用于简化 etcd 恢复的步骤。
恢复集群时,必须使用同一 z-stream 发行版本中获取的 etcd 备份。例如,OpenShift Container Platform 4.7.2 集群必须使用从 4.7.2 开始的 etcd 备份。
先决条件
-
使用具有
cluster-admin角色的用户访问集群,例如kubeadmin用户。 -
通过 SSH 访问所有 control plane 主机,允许主机用户成为
root用户;例如,默认的core主机用户。 -
包含之前 etcd 快照和来自同一备份的静态 pod 资源的备份目录。该目录中的文件名必须采用以下格式:
snapshot_<datetimestamp>.db和static_kuberesources_<datetimestamp>.tar.gz。
流程
使用 SSH 连接到每个 control plane 节点。
恢复过程启动后,Kubernetes API 服务器将无法访问,因此您无法访问 control plane 节点。因此,建议针对每个 control plane 主机都使用一个单独的终端来进行 SSH 连接。
重要如果没有完成这个步骤,将无法访问 control plane 主机来完成恢复过程,您将无法从这个状态恢复集群。
将 etcd 备份目录复制到每个 control plane 主机上。
此流程假设您将
backup目录(其中包含 etcd 快照和静态 pod 资源)复制到每个 control plane 主机的/home/core/assets目录中。如果尚未存在,您可能需要创建此assets文件夹。停止所有 control plane 节点上的静态 pod;一次只针对一个主机进行。
将现有 Kubernetes API Server 静态 pod 清单从 kubelet 清单目录中移出。
$ mkdir -p /root/manifests-backup$ mv /etc/kubernetes/manifests/kube-apiserver-pod.yaml /root/manifests-backup/使用以下命令验证 Kubernetes API 服务器容器是否已停止:
$ crictl ps | grep kube-apiserver | grep -E -v "operator|guard"命令输出应该为空。如果它不是空的,请等待几分钟后再重新检查。
如果 Kubernetes API 服务器容器仍在运行,使用以下命令手动终止它们:
$ crictl stop <container_id>对
kube-controller-manager-pod.yaml、kube-scheduler-pod.yaml最后为etcd-pod.yaml重复相同的步骤,。使用以下命令停止
kube-controller-managerpod:$ mv /etc/kubernetes/manifests/kube-controller-manager-pod.yaml /root/manifests-backup/使用以下命令检查容器是否已停止:
$ crictl ps | grep kube-controller-manager | grep -E -v "operator|guard"使用以下命令停止
kube-schedulerpod:$ mv /etc/kubernetes/manifests/kube-scheduler-pod.yaml /root/manifests-backup/使用以下命令检查容器是否已停止:
$ crictl ps | grep kube-scheduler | grep -E -v "operator|guard"使用以下命令停止
etcdpod:$ mv /etc/kubernetes/manifests/etcd-pod.yaml /root/manifests-backup/使用以下命令检查容器是否已停止:
$ crictl ps | grep etcd | grep -E -v "operator|guard"
在每个 control plane 主机上,保存当前的
etcd数据(将它移到backup目录中):$ mkdir /home/core/assets/old-member-data$ mv /var/lib/etcd/member /home/core/assets/old-member-data当
etcd备份恢复无法正常工作,且etcd集群必须恢复到当前状态,则这些数据将很有用。为每个 control plane 主机找到正确的 etcd 参数。
<ETCD_NAME>的值对每个 control plane 主机都是唯一的,它等于特定 control plane 主机上的清单/etc/kubernetes/static-pod-resources/etcd-certs/configmaps/restore-etcd-pod/pod.yaml文件中的ETCD_NAME变量的值。它可以通过以下命令找到:RESTORE_ETCD_POD_YAML="/etc/kubernetes/static-pod-resources/etcd-certs/configmaps/restore-etcd-pod/pod.yaml" cat $RESTORE_ETCD_POD_YAML | \ grep -A 1 $(cat $RESTORE_ETCD_POD_YAML | grep 'export ETCD_NAME' | grep -Eo 'NODE_.+_ETCD_NAME') | \ grep -Po '(?<=value: ").+(?=")'<UUID>的值可使用以下命令在 control plane 主机中生成:$ uuidgen注意<UUID>的值必须只生成一次。在一个 control plane 主机上生成UUID后,请不要在其他主机上再次生成它。相同的UUID会在后续步骤中的所有 control plane 主机上使用。ETCD_NODE_PEER_URL的值应设置为类似以下示例:https://<IP_CURRENT_HOST>:2380正确的 IP 可以从特定 control plane 主机的
<ETCD_NAME>中找到,使用以下命令:$ echo <ETCD_NAME> | \ sed -E 's/[.-]/_/g' | \ xargs -I {} grep {} /etc/kubernetes/static-pod-resources/etcd-certs/configmaps/etcd-scripts/etcd.env | \ grep "IP" | grep -Po '(?<=").+(?=")'<ETCD_INITIAL_CLUSTER>的值应设置为如下所示,其中<ETCD_NAME_n>是每个 control plane 主机的<ETCD_NAME>。注意使用的端口必须是 2380,而不是 2379。端口 2379 用于 etcd 数据库管理,并直接在容器中的 etcd start 命令中配置。
输出示例
<ETCD_NAME_0>=<ETCD_NODE_PEER_URL_0>,<ETCD_NAME_1>=<ETCD_NODE_PEER_URL_1>,<ETCD_NAME_2>=<ETCD_NODE_PEER_URL_2>1 - 1
- 指定每个 control plane 主机中的
ETCD_NODE_PEER_URL值。
<ETCD_INITIAL_CLUSTER>值在所有 control plane 主机上都是相同的。在后续步骤中,每个 control plane 主机都需要使用相同的值。
从备份中重新生成 etcd 数据库。
此类操作必须在每个 control plane 主机上执行。
使用以下命令将
etcd备份复制到/var/lib/etcd目录中:$ cp /home/core/assets/backup/<snapshot_yyyy-mm-dd_hhmmss>.db /var/lib/etcd在继续操作前,识别正确的
etcdctl镜像。使用以下命令从 pod 清单的备份中检索镜像:$ jq -r '.spec.containers[]|select(.name=="etcdctl")|.image' /root/manifests-backup/etcd-pod.yaml$ podman run --rm -it --entrypoint="/bin/bash" -v /var/lib/etcd:/var/lib/etcd:z <image-hash>检查
etcdctl工具的版本是创建备份的etcd服务器的版本:$ etcdctl version运行以下命令重新生成
etcd数据库,为当前主机使用正确的值:$ ETCDCTL_API=3 /usr/bin/etcdctl snapshot restore /var/lib/etcd/<snapshot_yyyy-mm-dd_hhmmss>.db \ --name "<ETCD_NAME>" \ --initial-cluster="<ETCD_INITIAL_CLUSTER>" \ --initial-cluster-token "openshift-etcd-<UUID>" \ --initial-advertise-peer-urls "<ETCD_NODE_PEER_URL>" \ --data-dir="/var/lib/etcd/restore-<UUID>" \ --skip-hash-check=true注意在重新生成
etcd数据库时,引号是必需的。
记录下在
added member日志中的值,例如:输出示例
2022-06-28T19:52:43Z info membership/cluster.go:421 added member {"cluster-id": "c5996b7c11c30d6b", "local-member-id": "0", "added-peer-id": "56cd73b614699e7", "added-peer-peer-urls": ["https://10.0.91.5:2380"], "added-peer-is-learner": false} 2022-06-28T19:52:43Z info membership/cluster.go:421 added member {"cluster-id": "c5996b7c11c30d6b", "local-member-id": "0", "added-peer-id": "1f63d01b31bb9a9e", "added-peer-peer-urls": ["https://10.0.90.221:2380"], "added-peer-is-learner": false} 2022-06-28T19:52:43Z info membership/cluster.go:421 added member {"cluster-id": "c5996b7c11c30d6b", "local-member-id": "0", "added-peer-id": "fdc2725b3b70127c", "added-peer-peer-urls": ["https://10.0.94.214:2380"], "added-peer-is-learner": false}- 退出容器。
-
在其他 control plane 主机上重复这些步骤,检查
added member日志中的值对于所有 control plane 主机都是一样的。
将重新生成的
etcd数据库移到默认位置。此类操作必须在每个 control plane 主机上执行。
将重新生成的数据库(上一个
etcdctl snapshot restore命令创建的member文件夹)移到默认的 etcd 位置/var/lib/etcd:$ mv /var/lib/etcd/restore-<UUID>/member /var/lib/etcd在
/var/lib/etcd目录中恢复/var/lib/etcd/member文件夹的 SELinux 上下文:$ restorecon -vR /var/lib/etcd/删除剩下的文件和目录:
$ rm -rf /var/lib/etcd/restore-<UUID>$ rm /var/lib/etcd/<snapshot_yyyy-mm-dd_hhmmss>.db重要完成后,
/var/lib/etcd目录只能包含文件夹member。- 在其他 control plane 主机上重复这些步骤。
重启 etcd 集群。
- 必须在所有 control plane 主机上执行以下步骤,但一次只针对一个主机执行。
将
etcd静态 pod 清单移回到 kubelet 清单目录,以便 kubelet 启动相关的容器:$ mv /root/manifests-backup/etcd-pod.yaml /etc/kubernetes/manifests验证所有
etcd容器是否已启动:$ crictl ps | grep etcd | grep -v operator输出示例
38c814767ad983 f79db5a8799fd2c08960ad9ee22f784b9fbe23babe008e8a3bf68323f004c840 28 seconds ago Running etcd-health-monitor 2 fe4b9c3d6483c e1646b15207c6 9d28c15860870e85c91d0e36b45f7a6edd3da757b113ec4abb4507df88b17f06 About a minute ago Running etcd-metrics 0 fe4b9c3d6483c 08ba29b1f58a7 9d28c15860870e85c91d0e36b45f7a6edd3da757b113ec4abb4507df88b17f06 About a minute ago Running etcd 0 fe4b9c3d6483c 2ddc9eda16f53 9d28c15860870e85c91d0e36b45f7a6edd3da757b113ec4abb4507df88b17f06 About a minute ago Running etcdctl如果这个命令的输出为空,请等待几分钟,然后再次检查。
检查
etcd集群的状态。在任何 control plane 主机上,使用以下命令检查
etcd集群的状态:$ crictl exec -it $(crictl ps | grep etcdctl | awk '{print $1}') etcdctl endpoint status -w table输出示例
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | https://10.0.89.133:2379 | 682e4a83a0cec6c0 | 3.5.0 | 67 MB | true | false | 2 | 218 | 218 | | | https://10.0.92.74:2379 | 450bcf6999538512 | 3.5.0 | 67 MB | false | false | 2 | 218 | 218 | | | https://10.0.93.129:2379 | 358efa9c1d91c3d6 | 3.5.0 | 67 MB | false | false | 2 | 218 | 218 | | +--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
重启其他静态 pod。
必须在所有 control plane 主机上执行以下步骤,但一次只针对一个主机执行。
将 Kubernetes API Server 静态 pod 清单重新移到 kubelet 清单目录中,以便 kubelet 使用命令启动相关的容器:
$ mv /root/manifests-backup/kube-apiserver-pod.yaml /etc/kubernetes/manifests验证所有 Kubernetes API 服务器容器是否已启动:
$ crictl ps | grep kube-apiserver | grep -v operator注意如果以下命令的输出为空,请等待几分钟,然后再次检查。
对
kube-controller-manager-pod.yaml和kube-scheduler-pod.yaml文件重复相同的步骤。使用以下命令重启所有节点中的 kubelet:
$ systemctl restart kubelet使用以下命令启动剩余的 control plane pod:
$ mv /root/manifests-backup/kube-* /etc/kubernetes/manifests/检查
kube-apiserver、kube-scheduler和kube-controller-managerpod 是否已正确启动:$ crictl ps | grep -E 'kube-(apiserver|scheduler|controller-manager)' | grep -v -E 'operator|guard'使用以下命令擦除 OVN 数据库:
for NODE in $(oc get node -o name | sed 's:node/::g') do oc debug node/${NODE} -- chroot /host /bin/bash -c 'rm -f /var/lib/ovn-ic/etc/ovn*.db && systemctl restart ovs-vswitchd ovsdb-server' oc -n openshift-ovn-kubernetes delete pod -l app=ovnkube-node --field-selector=spec.nodeName=${NODE} --wait oc -n openshift-ovn-kubernetes wait pod -l app=ovnkube-node --field-selector=spec.nodeName=${NODE} --for condition=ContainersReady --timeout=600s done
5.3.2.5. 恢复持久性存储状态的问题和解决方法 复制链接链接已复制到粘贴板!
如果您的 OpenShift Container Platform 集群使用任何形式的持久性存储,集群的状态通常存储在 etcd 外部。从 etcd 备份中恢复时,还会恢复 OpenShift Container Platform 中工作负载的状态。但是,如果 etcd 快照是旧的,其状态可能无效或过期。
持久性卷(PV)的内容绝不会属于 etcd 快照的一部分。从 etcd 快照恢复 OpenShift Container Platform 集群时,非关键工作负载可能会访问关键数据,反之亦然。
以下是生成过时状态的一些示例情况:
- MySQL 数据库在由 PV 对象支持的 pod 中运行。从 etcd 快照恢复 OpenShift Container Platform 不会使卷恢复到存储供应商上,且不会生成正在运行的 MySQL pod,尽管 pod 会重复尝试启动。您必须通过在存储供应商中恢复卷,然后编辑 PV 以指向新卷来手动恢复这个 pod。
- Pod P1 使用卷 A,它附加到节点 X。如果另一个 pod 在节点 Y 上使用相同的卷,则执行 etcd 恢复时,pod P1 可能无法正确启动,因为卷仍然被附加到节点 Y。OpenShift Container Platform 并不知道附加,且不会自动分离它。发生这种情况时,卷必须从节点 Y 手动分离,以便卷可以在节点 X 上附加,然后 pod P1 才可以启动。
- 在执行 etcd 快照后,云供应商或存储供应商凭证会被更新。这会导致任何依赖于这些凭证的 CSI 驱动程序或 Operator 无法正常工作。您可能需要手动更新这些驱动程序或 Operator 所需的凭证。
在生成 etcd 快照后,会从 OpenShift Container Platform 节点中删除或重命名设备。Local Storage Operator 会为从
/dev/disk/by-id或/dev目录中管理的每个 PV 创建符号链接。这种情况可能会导致本地 PV 引用不再存在的设备。要解决这个问题,管理员必须:
- 手动删除带有无效设备的 PV。
- 从对应节点中删除符号链接。
-
删除
LocalVolume或LocalVolumeSet对象(请参阅 StorageConfiguring persistent storage Persistent storage Persistent storage Deleting the Local Storage Operator Resources)。
5.3.3. 从 control plane 证书已过期的情况下恢复 复制链接链接已复制到粘贴板!
5.3.3.1. 从 control plane 证书已过期的情况下恢复 复制链接链接已复制到粘贴板!
集群可以从过期的 control plane 证书中自动恢复。
但是,您需要手动批准待处理的 node-bootstrapper 证书签名请求(CSR)来恢复 kubelet 证书。对于用户置备的安装,您可能需要批准待处理的 kubelet 服务 CSR。
使用以下步骤批准待处理的 CSR:
流程
获取当前 CSR 列表:
$ oc get csr输出示例
NAME AGE SIGNERNAME REQUESTOR CONDITION csr-2s94x 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending1 csr-4bd6t 8m3s kubernetes.io/kubelet-serving system:node:<node_name> Pending csr-4hl85 13m kubernetes.io/kube-apiserver-client-kubelet system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending2 csr-zhhhp 3m8s kubernetes.io/kube-apiserver-client-kubelet system:serviceaccount:openshift-machine-config-operator:node-bootstrapper Pending ...查看一个 CSR 的详细信息以验证其是否有效:
$ oc describe csr <csr_name>1 - 1
<csr_name>是当前 CSR 列表中 CSR 的名称。
批准每个有效的
node-bootstrapperCSR:$ oc adm certificate approve <csr_name>对于用户置备的安装,请批准每个有效的 kubelet 服务 CSR:
$ oc adm certificate approve <csr_name>