如果你和大多数用户一样,你可能已经看中了 Kubernetes,至少部分原因是它能够从故障中自动恢复。当然,Kubernetes 在保持你的工作负载正常运行方面也做得很好。然而,与任何复杂的系统一样,总是有失败的空间。无论这种故障是由于某个节点上的硬件故障,甚至是 etcd 集群上的数据丢失等原因,我们都希望有相应的系统来确保我们能够及时可靠地恢复。

高可用性

任何灾难恢复策略的第一条原则是,首先要设计好你的系统,将失败的可能性降到最低。自然,设计一个万无一失的系统是不可能的,但我们在构建时应该始终考虑到最坏的情况。

在构建生产级 Kubernetes 集群时,最佳实践总是决定了关键组件的高度可用。在某些情况下,如API服务器,这些可能具有主动-被动的配置,而像调度器和控制器管理器这样的项目,这些以主动-被动的方式运行。当这些控制面部署得当时,用户应该不会注意到甚至发生了故障。

同样,我们建议你的 etcd 备份存储以三节点或五节点集群配置部署。你当然可以部署更大的集群(总是使用奇数成员),但这种规模的集群应该足以满足绝大多数用例。etcd 集群的故障容忍度随着成员数量的增加而增加:三节点集群的故障容忍度为一个节点,五节点集群的故障容忍度为两个节点。但是,随着 etcd 集群规模的增大,集群的性能可能会慢慢降低。在选择集群大小的时候,一定要确保自己的 etcd 负载在预期范围内。

:::info 理解 Kubernetes 控制平面的故障通常不会影响数据平面。换句话说,如果你的 API Server、控制器管理器或调度器发生故障,你的 Pod 通常会继续按原样运行。在大多数情况下,在控制平面重新上线之前,你根本无法对集群进行更改。 :::

状态

每一个灾难恢复解决方案的核心问题是:“如何恢复到一个定义明确的先前状态?” 我们要确保,当灾难发生时,我们有所有数据的副本,我们需要恢复到操作状态。

:::tips 幸运的是,通过 Kubernetes,集群的大部分运行状态都集中在 etcd 集群中。因此,我们花了大量的时间来确保一旦发生故障,我们可以重新构建其内容。 :::

但 etcd 并不是我们关心的唯一状态。我们还需要确保我们对部署过程中创建(或在某些情况下提供)的一些静态资产进行备份。以下是应该安全收起的项目:

  • Kubernetes API Server 使用的所有PKI资产:这些通常位于 /etc/kubernetes/pki 目录中。
  • 任何秘密加密密钥:这些密钥存储在静态文件中,由 API Server 参数中的 --experimental-encryption-provider-config 指定。如果这些密钥丢失,任何秘密数据都无法恢复。
  • 任何管理员凭证:大多数部署工具(包括 kubeadm)都会创建静态管理员凭证,并在 kubeconfig 文件中提供。虽然这些凭证可以重新创建,但在集群外安全地存储它们可能会减少恢复时间。

应用数据

除了重建 Kubernetes 本身所需的所有状态外,恢复有状态的 Pod 将毫无用处,除非我们也恢复与这些 Pod 相关的任何持久性数据。

持久化存储

用户有多种方式可以在 Kubernetes 内持久化数据。如何备份这些数据取决于你的环境。

:::info 例如,在云提供商中,它可能只是简单地将任何持久化卷重新连接到各自的 Pod 上,其工作假设是你的 Kubernetes 故障与持久化卷的可用性无关。您也可以依赖支持卷本身的底层架构。例如,对于基于 Ceph 的卷,拥有数据的多个副本可能就足够了。 :::

您实现应用数据备份的方式在很大程度上取决于您为卷如何呈现给 Kubernetes 所选择的实现。当你制定更广泛的灾难恢复策略时,请记住这一点。

本地数据

数据备份中经常被忽视的一个方面是,用户有时会在不知不觉中把关键数据持久化到节点的本地磁盘上。这种情况在企业内部环境中尤其常见,因为在这种环境中,网络附加存储可能并不总是存在。如果没有适当的防护措施(例如,PodSecurityPolicys 和/或更通用的接纳控制器),用户可能会利用 emptyDirhostPath 卷,可能会对这些数据的寿命持有不正确的假设。

:::info 回顾我们在第 7 章中关于准入控制的讨论。如果你想对本地磁盘访问实施限制,这些可以通过 PodSecurityPolicy 来实现,主要是卷和allowHostPaths 控制。 :::

甚至可能不是遇到这个问题的故障场景。因为工人节点被广泛认为是短暂的,即使是有计划的维护或退役的节点,也可能给你的用户带来糟糕的体验。一定要确保有适当的控制措施。

工作节点

我们可以认为工作节点是可以替换的。当我们为工作节点设计灾难恢复策略时,我们只需要有一个流程,据此可以可靠地重新创建一个工作节点。如果您已将 Kubernetes 部署到云提供商,那么任务通常就像启动一个新实例并将该工作者加入到控制平面一样简单。在裸机环境中(或那些没有 API 导向的基础架构),这个过程可能会更繁琐一些,但大部分会是相同的。

如果你能够识别出某个节点即将发生故障,或者在需要进行维护的情况下,Kubernetes 提供的两个命令可能会有所帮助。

:::tips 首先,kubectl cordon 在高流失集群中尤为重要,它可以使节点不可调度。这可以帮助阻止新的 Pod 潮影响我们对工人节点执行恢复动作的能力。其次,kubectl drain 命令允许我们从目标节点上删除和重新安排所有正在运行的 Pod。这在我们打算从集群中移除一个节点的情况下非常有用。 :::

etcd

由于 etcd 集群保留了其数据集的多个副本,因此完全失败的情况相对较少。然而,备份etcd始终被认为是生产集群的最佳实践。

就像其他数据库一样,etcd将其数据存储在磁盘上,随之而来的是我们可以用各种方式来备份这些数据。在最底层,我们可以使用块和文件系统快照,这可能效果不错。但是,在尝试备份时,需要进行大量的协调工作。在这两种情况下,你需要确保 etcd 已经静止,通常是通过停止打算执行备份的 etcd 成员上的 etcd 进程。此外,为了确保所有飞行中的数据都已保存,您需要确保首先冻结底层文件系统。正如您所看到的,这可能会变得相当麻烦。

这种技术可能会在备份 etcd 的网络连接块设备上开始有意义。许多建立在公共云环境中的集群选择使用这种技术,因为它缩短了恢复的时间。这些用户不需要用备份替换磁盘上的数据,而只需要将现有的 etcd 数据卷重新连接到新的 etcd 成员节点上,然后,就可以恢复业务了。虽然这种解决方案可能可行,但有很多原因导致它可能不那么理想。其中最主要的是围绕数据一致性的担忧,因为这种方法相对难以正确执行。

最常见的方法是利用原生的 etcd 命令行工具,尽管会导致恢复时间稍长:

  1. ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save etcd-`date +%Y%m%d`.db

这可以针对一个活动的 etcd 成员运行,生成的文件应该从集群中卸载,并存储在一个可靠的位置,如对象存储。

如果你需要还原,你只需要执行这个名字恰当的还原命令:

  1. ETCDCTL_API=3 etcdctl snapshot restore etcd-$DATE.db --name $MEMBERNAME

针对新群集的每一个替换成员来做这件事。

虽然所有这些备份策略都是可行的,但有一些重要的注意事项需要考虑。

首先,在使用这两种方法进行备份时,要认识到你正在备份整个 etcd 关键空间的事实。它是备份时 etcd 状态的完整副本。虽然我们的目标通常是创建一个副本,但在某些情况下,我们可能并不真正想要整个备份。也许我们只是想快速地恢复生产 Namespace。对于这种类型的恢复,我们是不加区别地恢复。

其次,就像任何类型的数据库备份一样,如果消费应用程序(在我们的例子中,Kubernetes 本身)在备份过程中没有静止,可能会出现瞬时状态,而这种状态没有持续应用到备份存储中。这种极易出现问题的可能性很小,但还是存在的。

最后,如果你启用了任何 Kubernetes Aggregate API 服务器,或者使用了 etcd 支持的 Calico 实现(这两者都使用自己的 etcd 实例),如果你只针对集群的主 etcd 端点,这些将不会被备份。你将需要制定额外的策略来捕获和恢复这些数据。

:::info 如果你使用的是托管的 Kubernetes 产品,你可能无法直接访问 etcd,甚至无法访问备份 etcd 的磁盘。在这种情况下,你需要利用不同的备份和恢复方法。 :::

Ark

在 Kubernetes 集群的备份和恢复中,有一款专门的工具被广泛使用,它就是来自 Heptio 的 Ark。这个工具不仅关注 Kubernetes 资源数据的管理,同时也是一个管理应用数据的框架。

Ark 与我们已经介绍过的方法不同的是,它是可以感知 Kubernetes 的。Ark 不是盲目地备份 etcd 数据,而是通过 Kubernetes API 本身的方式来执行备份。这样可以确保数据始终保持一致,而且可以采取更有选择性的备份策略。我们来考虑几个例子:

  • 部分备份和恢复:因为 Ark 是 Kubernetes 感知的,所以它能够促进更高级的备份策略。例如,如果你对只备份生产工作负载感兴趣,你可以使用一个简单的标签选择器:ark backup create prod -backup --selector env=prod,这将会备份所有带有 env=prod 标签的资源。
  • 恢复到新环境:Ark 能够将备份恢复到一个全新的集群,甚至恢复到现有集群内的一个新的 Namespace。除了灾难恢复的主题,这也可以用来促进有趣的测试场景。
  • 部分恢复:在停机期间,通常最好先恢复最关键的系统。通过部分恢复, Ark 允许您确定恢复资源的优先级。
  • 持久数据备份:Ark 能够与各种云提供商集成,自动快照持久卷。此外,它还包括一个钩子机制,用于在快照之前和之后执行文件系统冻结等操作。
  • 计划备份:在集群服务管理状态下,Ark 能够调度备份。这对于确保定期进行备份特别有用。
  • 集群外备份:Ark 集成了各种 S3 兼容的对象存储解决方案。虽然这些解决方案可以在集群上运行,但建议将这些备份卸载,以便在发生故障时可以使用。

您可能不需要所有这些功能,但由于 Ark 提供了广泛的自由度,您可以选择对您的备份解决方案有意义的部分。

总结

在为您的 Kubernetes 集群设计灾难恢复策略时,有许多方面需要考虑。你如何设计这个策略取决于你对互补技术的选择,以及你的特定用例的细节。在你建立这块肌肉的时候,一定要定期锻炼你用全自动解决方案完全恢复生产系统的能力。这不仅能让你为失败做好准备,还能帮助你更全面地思考你的部署策略。当然,我们希望你永远不需要使用刚才介绍的技术。但如果有需要,你会因为事先考虑过这些情况而变得更好。