Kubernetes实战:构建生产级应用平台
上QQ阅读APP看书,第一时间看更新

4.1 存储注意事项

在介绍Kubernetes存储模式和选项之前,我们应该先围绕潜在的存储需求分析一些关键点。在基础设施和应用层面,必须考虑到以下要求:

•访问模式

•卷的扩展

•卷的配置

•备份和恢复

•块设备、文件存储和对象存储

•临时数据

•选择一个存储服务商

4.1.1 访问模式

有三种访问模式可供应用程序支持。

ReadWriteOnce(RWO)

单个Pod可以对卷进行读写。

ReadOnlyMany(ROX)

多个Pod可以读取卷。

ReadWriteMany(RWX)

多个Pod可以读取和写入卷。

对于云本地应用程序,RWO是迄今为止最常见的模式。当利用常见的服务商,如Amazon Elastic Block Storage(EBS;https:// aws.amazon.com/ebs)或Azure Disk Storage(https://oreil.ly/wAtBg)时,你将会被限制在RWO模式,因为磁盘只能连接到一个节点。虽然这种限制可能看起来有问题,但大多数云原生应用程序在这种存储中工作得最好,因为卷是它们专用的,并提供高性能的读或写。

很多时候,我们发现传统的应用程序对RWX有要求。通常情况下,它们被构建来对网络文件系统(NFS)进行访问(https://oreil.ly/OrsBR)。当服务需要共享状态时,通常有比通过NFS共享数据更优雅的解决方案。例如,使用消息队列或数据库。此外,如果一个应用程序希望共享数据,通常最好是通过API公开,而不是授予对其文件系统的访问。这使得RWX的许多用例有时是值得怀疑的。除非NFS是正确的设计选择,否则平台构建团队可能面临艰难的选择——是提供与RWX兼容的存储,还是要求开发人员重新架构应用程序?如果需要支持ROX或RWX,有几个服务商可以与之集成,如Amazon Elastic File System(EFS)(https://aws.amazon.com/efs)和Azure File Share(https://oreil.ly/u6HiQ)。

4.1.2 卷的扩展

随着时间的推移,一个应用程序可能会填满为其分配的卷。这可能会产生一个问题,因为用一个更大的卷来替换该卷将需要迁移数据。这方面的解决方案便是支持卷的扩展。从容器协调器(如Kubernetes)的角度来看,这涉及几个步骤:

1.向协调器请求额外的存储(例如,通过PersistentVolumeClaim)。

2.通过存储服务商扩大卷的大小。

3.扩展文件系统以利用更大的卷。

一旦完成卷的扩展,Pod将可以访问额外的空间。这个功能取决于我们对存储后端的选择,以及Kubernetes集成能否满足上述步骤。我们将在本章后面探讨一个卷的扩展的例子。

4.1.3 卷的配置

有两种配置模式可供使用:动态配置和静态配置。静态配置假设卷是在节点上创建以供Kubernetes使用的。动态配置是指驱动程序在集群内运行,并通过与存储服务商通信来满足工作负载的存储请求。在这两种模式中,动态配置是首选。通常情况下,两者之间的选择是你的底层存储系统是否有一个兼容的Kubernetes驱动程序的问题。我们将在本章后面深入讨论这些驱动程序。

4.1.4 备份和恢复

备份是存储中最复杂的功能之一,特别是当需要自动恢复时。在一般情况下,备份是一个数据的副本,它被储存起来,以便在数据丢失的情况下使用。通常,我们要平衡备份策略和存储系统的可用性保证。虽然备份始终是重要的,但当我们的存储系统有副本时,备份就不那么重要了,因为硬件的损失不会导致数据的损失。另一个需要关注的问题是应用程序可能需要不同的程序来备份和恢复。可以在任何时候对整个集群进行备份和恢复的想法通常是不切实际的,或者说这需要非常大的工程量才能实现。

决定谁应该负责应用程序的备份和恢复可能是一个组织内最具挑战性的争论之一。可以说,提供恢复功能作为一个平台服务可以是一个“不错的选择”。然而,当我们面对特定的应用程序时可能会引发问题,例如当一个应用程序不能重新启动并且需要执行一些只有开发者知道的操作时。

最受欢迎的Kubernetes状态和应用程序状态的备份解决方案之一是Project Velero(https://velero.io)。如果你有跨集群迁移或恢复的想法,Velero可以帮你备份Kubernetes对象。此外,Velero支持卷快照的调度。随着我们在本章中对卷快照的深入研究,我们将了解到,安排和管理快照的能力并没有被考虑在内。更确切地说,我们经常被赋予快照的基本要素,但需要围绕它们定义一个调度流程。最后,Velero支持备份和恢复的hook方法。这些使我们能够在执行备份或恢复之前在容器中运行命令。例如,一些应用程序可能需要在进行备份之前停止ping流量或触发刷新。使用Velero的hook方法就可以做到这一点。

4.1.5 块设备、文件存储和对象存储

我们的应用程序所期望的存储类型是适合底层存储且可以与Kubernetes集成的。应用程序最常使用的存储类型是文件存储。文件存储是一个具有文件系统的块设备。这使得应用程序能够以我们在任何操作系统上熟悉的方式写入文件。

文件系统的底层是块设备。与其在上面建立一个文件系统,不如提供这样的设备,使应用程序可以直接与原始块通信。虽然文件系统会增加写入数据的开销,但在现代软件开发中,关注文件系统的开销是很罕见的。然而,如果你的用例需要与原始块设备直接互动,这是某些存储系统可以支持的。

还有一种存储类型是对象存储。对象存储与文件存储的区别在于没有传统的层次结构。对象存储使开发者能够采取非结构化数据,给它一个唯一的标识符,在它周围添加一些元数据,并存储它。云服务商的对象存储[如Amazon S3(https://aws.amazon.com/s3)]已经成为很多组织托管图像、二进制文件等的最佳解决方案。它的全功能网络API和访问控制更是加速了这种流行。对象存储最常见的模式是与应用程序本身进行交互,其中应用程序使用一个库来验证并与服务商进行交互。由于与对象存储交互接口的标准化程度较低,因此将其整合为应用程序可以透明地进行互动的平台服务的情况并不常见。

4.1.6 临时数据

存储意味着超出Pod生命周期的持久性,而同时也需要支持临时数据的使用。默认情况下,向自己的文件系统写入的容器将利用临时存储。如果容器重新启动,这个存储就会丢失。emptyDir(https://oreil.ly/86zjA)卷类型可用于适应重启的临时存储,还可以用来在同一个Pod中的容器之间共享文件。

使用临时数据的最大风险是需要确保你的Pod不会消耗太多主机的存储容量。虽然每个Pod使用4Gi可能看起来不多,但考虑到一个节点可以运行数百个甚至数千个Pod,其消耗的容量就很多了。Kubernetes支持限制命名空间中Pod可使用的临时存储容量的能力。这些功能的配置将在第12章中讨论。

4.1.7 选择一个存储服务商

你并不缺乏可用的存储服务商。从你可以自己管理的存储解决方案(如Ceph)到完全托管的系统(如Google Persistent Disk或Amazon Elastic Block Store),可选择范围非常广泛。这些选项的差异远远超出了本书的范围。然而,我们确实建议了解存储系统的能力,以及这些能力中哪些容易与Kubernetes集成。这将使我们了解到一个解决方案相对于另一个解决方案能满足你的应用需求的程度。此外,在你可以管理自己的存储系统的情况下,考虑尽可能使用你有操作经验的东西,因为在引入Kubernetes的同时引入一个新的存储系统,会给你的组织增加很多新的操作复杂性。