Kubernetes上运行数据库:是最佳选择吗?

发表时间: 2022-09-01 11:16

数据库如何在 Kubernetes 上运行?如果可以,哪些类型的数据库和数据最适合使用 K8s?让我们一起来看看。

本文由RadonDB 开源社区组织翻译,原文链接:
https://www.containiq.com/post/should-you-run-a-database-on-kubernetes

作者 | Ricardo Castro
出品 | RadonDB 开源社区

Kubernetes 是用于自动部署、扩展和管理容器化应用程序的一个开源的容器编排解决方案。尽管 Kubernetes 最初是为无状态应用程序设计的,但随着有状态工作负载的日益流行,Kubernetes 也可以于管理有状态应用程序。

通常情况下,容器是无状态的,如果容器崩溃或需要重启,容器中的数据肯定会丢失。作为一个容器编排器,Kubernetes 会保持定期重启并在节点间移动容器。无论 Kubernetes 对运行应用程序的容器做了什么,这对于需要保存数据的有状态工作负载来说都是一个重要的问题。

众所周知,数据库服务器是一个有状态的应用程序。

那数据库如何在 Kubernetes 上运行?Kubernetes 是否有机制来管理此类应用程序?如果是这样,什么类型的数据库和数据最适合使用它?

在这篇文章中,我们将找到答案。


运行数据库的不同方式


以企业中运行数据库服务器的不同方式为例分为:

本地自有数据库:目前许多公司仍然选择使用虚拟机在本地或云上托管数据库服务器。企业负责设置数据库服务器、设置其安全性、安装补丁、升级、配置存储、提供高可用性、扩展、备份以及执行其他的数据库管理员操作。这是手动程度最高的方式,但这种方式可以完全控制数据库和数据。

云上托管数据库:大多数现代企业会选择 Amazon RDS、Azure 数据库、谷歌云数据库 或 Instaclustr 等在云上部署和扩展数据库服务器更容易的解决方案。供应商负责存储、计算、网络带宽、安装、升级和高可用性等。作为消费者的企业只需将数据库托管在供应商提供的一个实例上,该实例运行你选择的数据库引擎(如 SQL 或 NoSQL)。

Kubernetes 托管数据库:该方式是以上两种方式的混合体。你可以在本地或云端运行 Kubernetes 或者使用托管服务。通过这种方法,你可以利用 Kubernetes 的许多优势,如自动调度、自修复或水平伸缩。但数据库的使用(如性能调优、备份和恢复)仍需要你注意,并且可能会由于一些容器化特点而略有不同。


持久性存储和 K8s 的其他特性


尽管开发 Kubernetes 的目的是管理不需要数据持久性的容器化应用程序,但它现在也提供了管理有状态应用程序的解决方案。持久卷( Persistent volumes 简称 PV) 提供了一个 API,允许 Kubernetes 管理员管理卷,它与更多存储种类 一起提供了一种安全而抽象的方式来存储和管理数据。

然而,云是不可预测的,Kubernetes 经常需要重启和重新构建 pods。因此,持久卷很难在节点间移动数据,并同时确保它们连接到正确的容器。更复杂的是,一些数据库需要运行在多节点集群配置中。

Kubernetes 1.5 版本中引入了一些设计来帮助解决这些问题。StatefulSets 确保 pods 基于相同的容器规范,即使它们被移动到另一个节点也保持唯一的 ID。通过唯一 ID 将 pods 与持久卷耦合起来,即使在重新调度它们时,也可以维护工作负载的状态。DaemonSets 虽然稍微复杂一些,但也是在集群的每个节点上运行工作副本的一种方式。

分布式有状态工作负载通常需要一系列预定义资源无法处理的复杂操作。例如,分布式数据库可能需要在数据库节点(在 Kubernetes 中,是一个 pod)出现故障时执行一组特定的操作。这类操作的例子可以是选举领导者、平衡数据等等。

原生 Kubernetes 功能无法真正处理这些情况,但其自定义资源(Custom resources)可以提供帮助。Custom resources 允许 Kubernetes API 使用领域特定的逻辑进行扩展,定义新的资源类型和控制器。Operator 模式通过帮助开发自定义解决方案,利用自定义资源来管理应用程序及其组件。

OSS 框架,如 kubebuilder,或 Operator Framework,提供了构建块来创建 Operator,如 Postgres Operator、MySQL Operator for Kubernetes, Elastic Cloud on Kubernetes (ECK),或 K8ssandra。


分布式数据库的特性


大多数数据库引擎都提供了一种或多种方式来分发数据并使其具有高可用性。当选择要在 Kubernetes 上运行数据库时,你需要考虑以下特性:

复制:数据库是否支持复制?如果支持,它支持什么类型的复制(如:双向复制、事务复制和快照)?这将有助于提高可靠性、容错性和可访问性。
分片:数据库是否能够对数据进行分区,并在不同的实例(即 pod)中保存不同的片段?这可以帮助优化冗余和分散负载。
故障转移:数据库是否能够从主节点、读写节点切换到其他只读节点并将只读节点提升为主节点?这也将有助于提高可靠性、容错性和可访问性。
可伸缩性:数据库是否具备可伸缩性(向内扩展和向外扩展)?Kubernetes 为水平扩展铺平了道路,但是数据库需要根据需要添加或删除实例。这可以帮助处理增加的负载或在负载下降时降低成本。具有这些特性的数据库(例如:MySQL、PostgreSQL、ClickHouse、Elasticsearch、MongoDB 或 Cassandra 等)可以更轻松地应对异构云环境的不确定性。

数据可用性的考虑


由于 pod 和计算节点在本质上通常是临时的,因此,Kubernetes 更适合于某些类型的数据。重要的是要了解数据的重要性,以及它必须在多大程度上可用。

为了实现高可用性,一些数据库引擎使用所谓的最终一致性模型。最终一致性是一种技术,它确保如果给定的数据块没有新的更新,所有对它的访问都将返回最后更新的值。它假设,在任何时间点,不同节点的数据可能存在一些不一致(取决于从哪里读取它),因为它正在不断更新,但是一旦更新完成,所有节点都将拥有它的相同副本,并且所有客户端请求都将获得相同的数据。当你在 Kubernetes 中运行数据库系统时,需要从业务角度来看这是否可接受。

一些数据库引擎可以处理故障转移(例如,当运行数据的主副本的 pod 重新调度或崩溃时),但备用节点恢复并承担主要节点角色可能需要一些时间。你需要考虑在这种情况下,可以承受多少数据不可用,以及是否可以接受使用旧数据。

如你所见,这完全取决于业务需求。处理瞬态数据(如缓存层)、只读数据(如查找表)或可轻松重建的数据(如 API 输出)的工作负载时,很显然更适合在 Kubernetes 上。


总结

作为一种容器编排技术,Kubernetes 简化了许多常见的操作问题,例如调度、自动扩展或故障转移。虽然它非常适用于无状态工作负载,但有状态工作负载(如数据库)还有其他需要解决的问题。我们已经看到:

  • 持久卷和存储类提供了一种安全而抽象的方式来管理数据;

  • 通过允许将 pod 与持久数据绑定,可以在这些概念的基础上构建 StatefulSet 和 DaemonSet;

  • 自定义资源和 Operator 可以帮助为需要数据持久性的应用程序提供自定义逻辑。但是,重要的是要考虑对要在 Kubernetes 上运行的数据库引擎的可用支持,以及要存储的数据类型和数据的可用性要求。在 Kubernetes 中运行服务需要应对一定程度的波动性。

因此,Kubernetes 上更适合部署可以处理复制、分片和故障转移的数据库。同样,Kubernetes 托管的理想数据是可以轻松快速重新生成的数据。归根结底,这将取决于业务需要的容错能力。

云原生时代,Kubernetes 已成为运行云原生数据库的最佳选择,在《新程序员 003》的云原生专题中,Kubernetes 联合创始人 Brendan Burns 深入分享了 Kubernetes 的技术变革和未来演进,来自蚂蚁资深技术专家王旭分享了《Kubernetes 与云原生运行时的前世今生》等内容。