Table of Contents generated with DocToc
OpenEBS
简介
OpenEBS是什么?
OpenEBS是一种开源云原生存储解决方案,托管于CNCF基金会,目前该项目处于沙箱阶段,
OpenEBS是一组存储引擎,允许您为有状态工作负载(StatefulSet)和Kubernetes平台类型选择正确的存储解决方案。
在高层次上,OpenEBS支持两大类卷——本地卷和复制卷
OpenEBS是Kubernetes本地超融合存储解决方案,它管理节点可用的本地存储,并为有状态工作负载提供本地或高可用的分布式持久卷。
作为一个完全的Kubernetes原生解决方案的另一个优势是,管理员和开发人员可以使用kubectl、Helm、
Prometheus、Grafana、Weave Scope等Kubernetes可用的所有优秀工具来交互和管理OpenEBS
OpenEBS能做什么?
OpenEBS管理k8s节点上存储,并为k8s有状态负载(StatefulSet)提供本地存储卷或分布式存储卷。
本地卷(
Local Storage)OpenEBS可以使用宿主机裸块设备或分区,或者使用Hostpaths上的子目录,或者使用LVM、ZFS来创建持久化卷- 本地卷直接挂载到
Stateful Pod中,而不需要OpenEBS在数据路径中增加任何开销 OpenEBS为本地卷提供了额外的工具,用于监控、备份/恢复、灾难恢复、由ZFS或LVM支持的快照等
对于分布式卷(即复制卷)
OpenEBS使用其中一个引擎(Mayastor、cStor或Jiva)为每个分布式持久卷创建微服务- 有状态
Pod将数据写入OpenEBS引擎,OpenEBS引擎将数据同步复制到集群中的多个节点。OpenEBS引擎本身作为pod部署,并由Kubernetes进行协调。 当运行Stateful Pod的节点失败时,Pod将被重新调度到集群中的另一个节点,OpenEBS将使用其他节点上的可用数据副本提供对数据的访问 - 有状态的
Pods使用iSCSI(cStor和Jiva)或NVMeoF(Mayastor)连接OpenEBS分布式持久卷 OpenEBS cStor和Jiva专注于存储的易用性和持久性。它们分别使用自定义版本的ZFS和Longhorn技术将数据写入存储。OpenEBS Mayastor是最新开发的以耐久性和性能为设计目标的引擎,高效地管理计算(大页面、核心)和存储(NVMe Drives),以提供快速分布式块存储
注意:
OpenEBS分布式块卷被称为复制卷,以避免与传统的分布式块存储混淆,传统的分布式块存储倾向于将数据分布到集群中的许多节点上。
复制卷是为云原生有状态工作负载设计的,这些工作负载需要大量的卷,这些卷的容量通常可以从单个节点提供,而不是使用跨集群中的多个节点分片的单个大卷
对比传统分布式存储
OpenEBS与其他传统存储解决方案不同的几个关键方面:
使用微服务体系结构构建,就像它所服务的应用程序一样。
OpenEBS本身作为一组容器部署在Kubernetes工作节点上。使用Kubernetes本身来编排和管理OpenEBS组件完全建立在用户空间,使其高度可移植性,以运行在任何操作系统/平台。
完全意图驱动,继承了
Kubernetes易用性的相同原则OpenEBS支持一系列存储引擎,因此开发人员可以部署适合于其应用程序设计目标的存储技术。 像Cassandra这样的分布式应用程序可以使用LocalPV引擎进行最低延迟的写操作。 像MySQL和PostgreSQL这样的单片应用程序可以使用使用NVMe和SPDK构建的Mayastor或基于ZFS的cStor来实现弹性。 像Kafka这样的流媒体应用程序可以在边缘环境中使用NVMe引擎Mayastor以获得最佳性能。
驱使用户使用OpenEBS的主要原因是:
- 在所有的
Kubernetes发行版上都是可移植的 - 提高了开发人员和平台
SRE的生产力 - 与其他解决方案相比,易于使用
- 优秀的社区支持
- 免费开源
本地卷类型
本地卷只能从集群中的单个节点访问。必须在提供卷的节点上调度使用Local Volume的Pods。
本地卷通常是分布式工作负载的首选,比如Cassandra、MongoDB、Elastic等,这些工作负载本质上是分布式的,并且内置了高可用性(分片)
根据附加到Kubernetes工作节点上的存储类型,您可以从不同的动态本地PV进行选择——Hostpath、Device、LVM、ZFS或Rawfile
可复制卷类型
复制卷顾名思义,是指将数据同步复制到多个节点的卷。卷可以支持节点故障。还可以跨可用性区域设置复制,以帮助应用程序跨可用性区域移动。
复制卷还能够提供像快照、克隆、卷扩展等企业存储特性。复制卷是有状态工作负载(如Percona/MySQL、Jira、GitLab等)的首选。
根据附加到Kubernetes工作节点的存储类型和应用程序性能需求,您可以从Jiva、cStor或Mayastor中进行选择
OpenEBS存储引擎建议
| 应用需求 | 存储类型 | OpenEBS卷类型 |
|---|---|---|
| 低时延、高可用性、同步复制、快照、克隆、精简配置 | SSD/云存储卷 | OpenEBS Mayastor |
| 高可用性、同步复制、快照、克隆、精简配置 | 机械/SSD/云存储卷 | OpenEBS cStor |
| 高可用性、同步复制、精简配置 | 主机路径或外部挂载存储 | OpenEBS Jiva |
| 低时延、本地PV | 主机路径或外部挂载存储 | Dynamic Local PV - Hostpath, Dynamic Local PV - Rawfile |
| 低时延、本地PV | 本地机械/SSD/云存储卷等块设备 | Dynamic Local PV - Device |
| 低延迟,本地PV,快照,克隆 | 本地机械/SSD/云存储卷等块设备 | OpenEBS Dynamic Local PV - ZFS , OpenEBS Dynamic Local PV - LVM |
总结:
- 多机环境,如果有额外的块设备(非系统盘块设备)作为数据盘,选用
OpenEBS Mayastor、OpenEBS cStor - 多机环境,如果没有额外的块设备(非系统盘块设备)作为数据盘,仅单块系统盘块设备,选用
OpenEBS Jiva - 单机环境,建议本地路径
Dynamic Local PV - Hostpath, Dynamic Local PV - Rawfile,由于单机多用于测试环境,数据可靠性要求较低。
由此看来,OpenEBS常用场景为以上三个场景
OpenEBS特性
容器附加存储
OpenEBS是一个容器附加存储(Container Attached Storage, CAS)的例子。
通过OpenEBS提供的卷总是被容器化。每个卷都有一个专用的存储控制器,用于提高有状态应用程序的持久性存储操作的敏捷性和粒度。
同步复制
同步复制是OpenEBS的一个可选的流行特性。
当与Jiva、cStor和Mayastor存储引擎一起使用时,OpenEBS可以同步复制数据卷以实现高可用性。
跨Kubernetes区域进行复制,从而为跨AZ设置提供高可用性。
这个特性对于使用GKE、EKS和AKS等云提供商服务上的本地磁盘构建高可用状态应用程序特别有用
快照和克隆
写时拷贝快照是OpenEBS另一个可选的流行特性。
使用cStor引擎时,快照是瞬时创建的,并且不受快照个数的限制。
增量快照功能增强了跨Kubernetes集群和跨不同云提供商或数据中心的数据迁移和可移植性。
对快照和克隆的操作完全以Kubernetes原生方法执行,使用标准kubectl命令。
常见的用例包括用于备份的高效复制和用于故障排除或针对数据的只读副本进行开发的克隆
备份和恢复
OpenEBS卷的备份和恢复可以通过开源的OpenEBS Velero插件与Kubernetes备份和恢复解决方案(如Velero(前身为Heptio Ark))协同工作。
经常使用OpenEBS增量快照功能,将数据备份到AWS S3、GCP object storage、MinIO等对象存储目标。
这种存储级别的快照和备份只使用增量数据进行备份,节省了大量的带宽和存储空间。
真正的
Kubernetes云原生存储
OpenEBS是Kubernetes上有状态应用程序的云原生存储,云原生意味着遵循松散耦合的体系结构。
因此,云原生、松散耦合体系结构的一般好处是适用的。
例如,开发人员和DevOps架构师可以使用标准的Kubernetes技能和实用程序来配置、使用和管理持久存储需求
减少存储
TCO高达50%
在大多数云上,块存储的收费是基于购买的多少,而不是使用的多少;
为了实现更高的性能,并在充分利用容量时消除中断的风险,容量经常被过度配置。
OpenEBS的精简配置能力可以共享本地存储或云存储,然后根据需要增加有状态应用程序的数据量。
可以动态添加存储,而不会中断暴露给工作负载或应用程序的卷。
某些用户报告说,由于使用了OpenEBS的精简配置,节省了超过60%的资源。
高可用性
由于OpenEBS遵循CAS架构,在节点故障时,Kubernetes将重新调度OpenEBS控制器,而底层数据则通过使用一个或多个副本来保护。
更重要的是——因为每个工作负载都可以利用自己的OpenEBS——不存在因存储丢失而导致系统大范围宕机的风险。
例如,卷的元数据不是集中的,它可能会像许多共享存储系统那样受到灾难性的通用中断的影响。
相反,元数据保持在卷的本地。丢失任何节点都会导致只存在于该节点上的卷副本的丢失。
由于卷数据至少在其他两个节点上进行了同步复制,因此当一个节点出现故障时,这些数据将在相同的性能级别上继续可用
CAS介绍
在CAS或容器附加存储(Container Attached Storage)体系结构中,存储在容器中运行,并且与存储绑定到的应用程序密切相关。
存储作为微服务运行,没有内核模块依赖关系。
像Kubernetes这样的编排系统编排存储卷,就像任何其他微服务或容器一样。CAS具有DAS和NAS的优点
非
CAS系统上的pv
在非CAS模型中,Kubernetes持久卷仍然与内核模块紧密耦合,使得Kubernetes节点上的存储软件本质上是单片的

基于
CAS系统上的pv

相反,CAS使您能够利用云原生应用程序的灵活性和可伸缩性。
定义Kubernetes PV (Persistent Volume)的存储软件是基于微服务架构的。
存储软件的控制平面(存储控制器)和数据平面(存储副本)作为Kubernetes Pods运行,因此,使您能够将云原生的所有优势应用到CAS。
CAS优势
- 敏捷
CAS中的每个存储卷都有一个容器化的存储控制器和相应的容器化副本。
因此,围绕这些组件的资源的维护和调优是真正敏捷的。
Kubernetes滚动升级功能可以实现存储控制器和存储副本的无缝升级。可以使用容器cGroups调优CPU和内存等资源配额。
- 存储策略粒度化
将存储软件容器化并将存储控制器专用于每个卷可以带来最大的存储策略粒度。
在CAS体系结构中,可以按卷配置所有存储策略。
此外,您可以监视每个卷的存储参数,并动态更新存储策略,以实现每个工作负载的预期结果。
随着卷存储策略中这种额外粒度级别的增加,存储吞吐量、IOPS和延迟的控制也会增加。
- 云原生
CAS将存储软件装入容器,并使用Kubernetes自定义资源定义(CRDs)来声明低级存储资源,如磁盘和存储池。
这个模型使存储能够无缝地集成到其他云原生工具中。
可以使用Prometheus、Grafana、Fluentd、Weavescope、Jaeger等云原生工具来供应、监控和管理存储资源
PV是CAS中的一个微服务
如上图所示,在CAS架构中,存储控制器和副本的软件完全是基于微服务的,因此不涉及内核组件。
通常,存储控制器POD被调度在与持久卷相同的节点上,以提高效率,副本POD可以被调度在集群节点上的任何位置。
每个副本使用本地磁盘、SAN磁盘和云磁盘的任意组合完全独立于其他副本进行配置。
这为大规模管理工作负载的存储分配提供了巨大的灵活性。
- 超融合非分布式
CAS架构没有遵循典型分布式存储架构。通过从存储控制器到存储副本的同步复制,存储变得高度可用。
卷副本的元数据不是在节点之间共享的,而是在每个本地节点上独立管理。
如果一个节点故障,存储控制器(在本例中是一个无状态容器)将在一个节点上轮转,该节点上运行着第二个或第三个副本,数据仍然可用。
与超融合系统类似,CAS中的卷的存储和性能是可扩展的。由于每个卷都有自己的存储控制器,因此存储可以在一个节点的存储容量允许的范围内进行扩展。
在给定的Kubernetes集群中,随着容器应用程序数量的增加,会增加更多的节点,从而提高存储容量和性能的整体可用性,从而使存储对新的应用程序容器可用。
这一过程与Nutanix等成功的超融合系统非常相似。
OpenESB架构介绍
OpenESB遵循容器附加存储(CAS)模型,每个卷都有一个专用的控制器POD和一组副本POD。
CAS体系结构的优点在CNCF博客 上进行了讨论。
OpenEBS操作和使用都很简单,因为它看起来和感觉上就像其他云原生和Kubernetes友好的项目。
OpenEBS有许多组件,可以分为以下类别:
- 控制面组件 -
Provisioner,API Server,volume exports,volume sidecars - 数据面组件 -
Jiva、cStor - 节点磁盘管理器 -
Discover,monitor, 管理连接k8s的媒介 - 与云原生工具的集成 - 已经与
Prometheus,Grafana,Fluentd、Jaeger集成
控制面
OpenEBS集群的控制平面通常被称为Maya
OpenEBS控制平面负责提供卷、相关的卷操作,如快照、克隆、创建存储策略、执行存储策略、导出Prometheus/grafana使用的卷指标,等等。

OpenEBS提供了一个动态提供程序,这是Kubernetes的标准外部存储插件。
OpenEBS PV提供者的主要任务是向应用程序PODS启动卷供应,并实现PV的Kubernetes规范。
m-apiserver开放存储的REST API,并承担大量卷策略处理和管理工作。
控制平面和数据平面之间的连通性使用Kubernetes sidecar模式。控制平面需要与数据平面通信的场景如下所示。
对于卷的统计,如
IOPS,吞吐量,延迟等--通过卷暴漏的sidecar实现使用卷控制器
pod执行卷策略,使用卷副本pod进行磁盘/池管理-通过卷管理sidecar实现
OpenEBS PV Provisioner

此组件作为POD运行,并做出配置决策,它的使用方式是:
开发人员用所需的卷参数构造一个声明,选择适当的存储类,并在YAML规范上调用kubelet。
OpenEBS PV动态提供程序与maya-apiserver交互,在适当的节点上为卷控制器pod和卷副本pod创建部署规范。
可以使用PVC规范中的注释来控制卷Pod(控制器/副本)的调度。
目前,OpenEBS Provisioner只支持一种绑定类型,即iSCSI。
Maya-ApiServer

m-apiserver作为POD运行。顾名思义,m-apiserver公开OpenEBS REST api
m-apiserver还负责创建创建卷pod所需的部署规范文件。
在生成这些规范文件之后,它将调用kube-apiserver来相应地调度这些pods。
OpenEBS PV提供者在卷发放结束时,将创建一个PV对象并将其挂载到应用程序pod上。
PV由控制器pod承载,控制器pod由不同节点中的一组副本pod支持。
控制器pod和复制pod是数据平面的一部分,在存储引擎部分有更详细的描述。
m-apiserver的另一个重要任务是卷策略管理。OpenEBS为表示策略提供了非常细粒度的规范。
m-apiserver解释这些YAML规范,将它们转换为可执行的组件,并通过容量管理sidecar来执行它们
Maya Volume Exporter
Maya卷导出器是每个存储控制器pod的sidecar
这些sidecar将控制平面连接到数据平面以获取统计信息。统计信息的粒度在卷级别。一些统计数据示例如下:
- 卷读取延迟
- 卷写入延迟
- 卷每秒读取速度
- 卷每秒写入速度
- 读取块大小
- 写入块大小
- 容量统计

这些统计信息通常由Prometheus客户端来拉取,该客户端在OpenBS安装期间安装和配置
卷管理
sidecar
Sidecars还用于将控制器配置参数和卷策略传递给卷控制器pod(卷控制器pod是一个数据平面),
并将副本配置参数和副本数据保护参数传递给卷副本pod。

数据面
OpenEBS数据平面负责实际的卷IO路径。存储引擎在数据平面实现实际的IO路径。
目前,OpenEBS提供了两个可以轻松插入的存储引擎。它们被称为Jiva和cStor。
这两个存储引擎都完全运行在Linux用户空间中,并基于微服务架构。
Jiva
Jiva存储引擎基于Rancher's LongHorn与gotgt开发实现, 使用go语言开发,并运行于用户命名空间下。
LongHorn控制器将输入的IO同步复制到LongHorn副本。该副本将Linux稀疏文件视为构建存储特性(如精简配置、快照、重建等)的基础。
cStor
cStor数据引擎使用C语言编写,具有高性能的iSCSI target和Copy-On-Write块系统,提供数据完整性、数据弹性和时间点的快照和克隆。
cStor有一个池特性,它以条带、镜像或RAIDZ模式聚合一个节点上的磁盘,以提供更大的容量和性能单位。
cStor还可以跨区域将数据同步复制到多个节点,从而避免节点丢失或节点重启导致数据不可用。
LocalPV
对于那些不需要存储级复制的应用程序,LocalPV可能是很好的选择,因为它能提供更高的性能。
OpenEBS LocalPV与Kubernetes LocalPV类似,不同之处在于它是由OpenEBS控制平面动态提供的,
就像任何其他常规PV一样。OpenEBS LocalPV有两种类型:hostpath LocalPV和device LocalPV。
hostpath LocalPV指的是主机上的子目录,LocalPV指的是在节点上发现的磁盘(可以是直接连接的,也可以是网络连接的)。
OpenEBS引入了一个LocalPV提供者,用于根据PVC和存储类规范中的一些标准选择匹配的磁盘或主机路径。
节点磁盘管理器
节点磁盘管理器(NDM)填补了使用Kubernetes管理有状态应用程序的持久存储所需的工具链的空白。
容器时代的DevOps架构师必须以一种自动化的方式满足应用程序和应用程序开发人员的基础设施需求,
这种方式可以跨环境提供弹性和一致性。这些要求意味着存储堆栈本身必须非常灵活,
以便Kubernetes和云原生生态系统中的其他软件可以轻松地使用这个堆栈。
NDM在Kubernetes的存储堆栈中起着基础性的作用,它统一了不同的磁盘,
并通过将它们标识为Kubernetes对象,提供了将它们汇聚的能力。
此外,NDM发现、提供、监视和管理底层磁盘的方式,可以让Kubernetes PV提供者(如OpenEBS和其他存储系统)和Prometheus管理磁盘子系统
CAS引擎
存储引擎概述
存储引擎是持久化卷IO路径的数据平面组件。
在CAS架构中,用户可以根据不同的配置策略,为不同的应用工作负载选择不同的数据平面。
存储引擎可以通过特性集或性能优化给定的工作负载。
操作员或管理员通常选择具有特定软件版本的存储引擎,并构建优化的卷模板,
这些卷模板根据底层磁盘的类型、弹性、副本数量和参与Kubernetes集群的节点集进行微调。
用户可以在发放卷时选择最优的卷模板,从而在给定的Kubernetes集群上为所有存储卷运行最优的软件和存储组合提供最大的灵活性。
存储引擎类型
OpenEBS提供了三种存储引擎
JivaJiva是OpenEBS 0.1版中发布的第一个存储引擎,使用起来最简单。它基于GoLang开发,内部使用LongHorn和gotgt堆栈。Jiva完全在用户空间中运行,并提供同步复制等标准块存储功能。Jiva通常适用于容量较小的工作负载,不适用于大量快照和克隆特性是主要需求的情况cStorcStor是OpenEBS 0.7版本中最新发布的存储引擎。cStor非常健壮,提供数据一致性,很好地支持快照和克隆等企业存储特性。 它还提供了一个健壮的存储池特性,用于在容量和性能方面进行全面的存储管理。cStor与NDM(Node Disk Manager)一起,为Kubernetes上的有状态应用程序提供完整的持久化存储特性OpenEBS Local PVOpenEBS Local PV是一个新的存储引擎,它可以从本地磁盘或工作节点上的主机路径创建持久卷或PV。CAS引擎可以从OpenEBS的1.0.0版本中获得。使用OpenEBS Local PV,性能将等同于创建卷的本地磁盘或文件系统(主机路径)。 许多云原生应用程序可能不需要复制、快照或克隆等高级存储特性,因为它们本身就提供了这些特性。这类应用程序需要以持久卷的形式访问管理的磁盘

SP存储池,表示Jiva自定义存储资源CVcStor卷,表示cStor卷自定义资源CVRcStor卷副本SPC存储池声明,表示cStor池聚合的自定义资源CSPcStor存储池,表示cStor Pool每个节点上的自定义资源
一个SPC对应多个CSP,相应的一个CV对应多个CVR
存储引擎声明
通过指定注释openebs来选择存储引擎。
StorageClass规范中的io/cas-type。StorageClass定义了提供程序的细节。为每个CAS引擎指定单独的供应程序。
cStor存储类规范文件内容
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: cStor-storageclass
annotations:
openebs.io/cas-type: cstor
cas.openebs.io/config: |
- name: StoragePoolClaim
value: "cStorPool-SSD"
provisioner: openebs.io/provisioner-iscsi
---
Jiva存储类规范文件内容
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: jiva-storageclass
annotations:
openebs.io/cas-type: jiva
cas.openebs.io/config: |
- name: StoragePool
value: default
provisioner: openebs.io/provisioner-iscsi
---
当cas类型为Jiva时,StoragePool的default值具有特殊含义。
当pool为默认值时,Jiva引擎将从容器(副本pod)本身的存储空间中为副本pod开辟数据存储空间。
当所需的卷大小很小(比如5G到10G)时,StoragePool default工作得很好,因为它可以容纳在容器本身内。
Local PV存储类规范文件内容-主机路径
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: localpv-hostpath-sc
annotations:
openebs.io/cas-type: local
cas.openebs.io/config: |
- name: BasePath
value: "/var/openebs/local"
- name: StorageType
value: "hostpath"
provisioner: openebs.io/local
---
Local PV存储类规范文件内容-主机设备
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: localpv-device-sc
annotations:
openebs.io/cas-type: local
cas.openebs.io/config: |
- name: StorageType
value: "device"
- name: FSType
value: ext4
provisioner: openebs.io/local
---
cStor、Jiva、LocalPV特性比较:
| 特性 | Jiva | cStor | Local PV |
|---|---|---|---|
| 轻量级运行于用户空间 | Yes | Yes | Yes |
| 同步复制 | Yes | Yes | No |
| 适合低容量工作负载 | Yes | Yes | Yes |
| 支持快照,克隆 | Basic | Advanced | No |
| 数据一致性 | Yes | Yes | NA |
| 使用Velero恢复备份 | Yes | Yes | Yes |
| 适合高容量工作负载 | No | Yes | Yes |
| 自动精简配置 | Yes | No | |
| 磁盘池或聚合支持 | Yes | No | |
| 动态扩容 | Yes | Yes | |
| 数据弹性(RAID支持) | Yes | No | |
| 接近原生磁盘性能 | No | No | Yes |
大多数场景推荐cStor,因其提供了强大的功能,包括快照/克隆、存储池功能(如精简资源调配、按需扩容等)。
Jiva适用于低容量需求的工作负载场景,例如5到50G。
尽管使用Jiva没有空间限制,但建议将其用于低容量工作负载。
Jiva非常易于使用,并提供企业级容器本地存储,而不需要专用硬盘。
有快照和克隆功能的需求的场景,优先考虑使用cStor而不是Jiva。
CAS引擎使用场景
如上表所示,每个存储引擎都有自己的优势。 选择引擎完全取决于应用程序的工作负载以及它当前和未来的容量和/或性能增长。 下面的指导原则在定义存储类时为选择特定的引擎提供一些帮助。
选择
cStor的理想条件
- 当需要同步复制数据并在节点上有多个磁盘时
- 当您从每个节点上的本地磁盘或网络磁盘池管理多个应用程序的存储时。
通过精简配置、存储池和卷的按需扩容、存储池的性能按需扩容等特性,实现对存储层的管理。
cStor用于在本地运行的Kubernetes集群上构建Kubernetes本地存储服务,类似于AWS EBS或谷歌PD。 - 当需要存储级快照和克隆能力时
- 当您需要企业级存储保护特性,如数据一致性、弹性(
RAID保护)。 - 如果您的应用程序不需要存储级复制,那么使用
OpenEBS主机路径LocalPV或OpenEBS设备LocalPV可能是更好的选择。
选择
Jiva的理想条件:
- 当您想要数据的同步复制,并且拥有单个本地磁盘或单个管理磁盘(如云磁盘(
EBS、GPD)),并且不需要快照或克隆特性时 Jiva是最容易管理的,因为磁盘管理或池管理不在这个引擎的范围内。Jiva池是本地磁盘、网络磁盘、虚拟磁盘或云磁盘的挂载路径。- 以下场景
Jiva更优于cStor:- 当程序不需要存储级的快照、克隆特性
- 当节点上没有空闲磁盘时。
Jiva可以在主机目录上使用,并且仍然可以实现复制。 - 当不需要动态扩展本地磁盘上的存储时。将更多磁盘添加到
Jiva池是不可能的,因此Jiva池的大小是固定的,如果它在物理磁盘上。 但是,如果底层磁盘是虚拟磁盘、网络磁盘或云磁盘,则可以动态地更改Jiva池的大小 - 容量需求较小。大容量应用通常需要动态增加容量,
cStor更适合这种需求
选择
OpenEBS主机路径LocalPV的理想条件:
- 当应用程序本身具备管理复制能力(例如:
es)时,不需要在存储层进行复制。在大多数这样的情况下,应用程序是作为statefulset部署的 - 高于
Jiva与cStor的读写性能需求 - 当特定应用程序没有专用的本地磁盘或特定应用程序不需要专用的存储时,建议使用
Hostpath。 如果您想跨多个应用程序共享一个本地磁盘,主机路径LocalPV是正确的方法
选择
OpenEBS主机设备LocalPV的理想条件:
- 当应用程序管理复制本身,不需要在存储层进行复制时。在大多数这种情况下,应用程序被部署为有状态集
- 高于
Jiva与cStor的读写性能需求 - 高于
OpenEBS主机路径LocalPV的读写性能需求 - 当需要接近磁盘性能时。该卷专用于写入单个
SSD或NVMe接口以获得最高性能
总结
- 如果应用程序处于生产中,并且不需要存储级复制,那么首选
LocalPV - 如果您的应用程序处于生产状态,并且需要存储级复制,那么首选
cStor - 如果应用程序较小,需要存储级复制,但不需要快照或克隆,则首选
Jiva
节点磁盘管理器(NDM)
节点磁盘管理器(NDM)是OpenEBS体系结构中的一个重要组件。
NDM将块设备视为需要监视和管理的资源,就像CPU、内存和网络等其他资源一样。
它是一个在每个节点上运行的守护进程,基于过滤器检测附加的块设备,并将它们作为块设备自定义资源加载到Kubernetes中。这些定制资源旨在通过提供类似于:
- 轻松访问
Kubernetes集群中可用的块设备清单 - 预测磁盘的故障,以帮助采取预防措施
- 允许动态地将磁盘挂载/卸载到存储
Pod中,而无需重新启动在磁盘挂载/卸载的节点上运行的相应NDM Pod
尽管做了上述所有工作,NDM还是有助于提供持久卷的总体简化。
NDM是在OpenEBS安装期间作为守护进程部署的。NDM daemonset发现每个节点上的磁盘,并创建一个名为Block Device或BD的自定义资源。
访问权限说明
NDM守护进程运行在容器中,必须访问底层存储设备并以特权模式运行。
NDM需要特权模式,因为它需要访问/dev、/proc和/sys目录来监视附加设备,还需要使用各种探测器获取附加设备的详细信息。
NDM负责发现块设备并过滤掉不应该被OpenEBS使用的设备;例如,检测有OS文件系统的磁盘。
NDM pod默认情况下在容器中挂载主机的/proc目录,然后加载/proc/1/mounts,以找到操作系统使用的磁盘
NDM守护程序功能
发现
Kubernetes节点上的块设备- 在启动时发现块设备-创建和/或更新状态。
- 维护集群范围内磁盘的唯一
id: 对WWN / PartitionUUID / FileSystemUUID / DeviceMapperUUID进行Hash计算
检测节点中添加/移除块设备,并更新块设备状态
- 添加块设备作为
Kubernetes自定义资源,具有以下属性:spec: 如果可用,将更新以下内容- 设备路径
- 设备链接
- 供应商和型号信息
WWN和序列号- 容量
- 扇区和区块大小
labels:- 主机名称(
kubernetes.io/hostname) - 块设备类型(
ndm.io/blockdevice-type) - Managed (
ndm.io/managed)
- 主机名称(
status: 状态可以有以下值Active: 节点上存在块设备Inactive: 给定节点上不存在块设备Unknown:NDM在块设备最后被检测到的节点上停止/无法确定状态
过滤器
- 为要创建块设备
CR的块设备类型配置过滤器。过滤器可以通过供应商类型、设备路径模式或挂载点进行配置 - 过滤器可以是包含过滤器,也可以是排除过滤器。它们被配置为
configmap。 管理员用户可以在OpenEBS安装时通过更改OpenEBS操作员yaml文件或helm值中的NDM configmap来配置这些过滤器。yaml文件。如果这些过滤器需要在安装后更新,那么可以遵循以下方法之一:- 使用
operator方式安装OpenEBS。在Yaml文件中,更新configmap中的过滤器并应用operator.yaml - 如果
OpenEBS是使用helm安装的,更新values.yaml中的configmap并使用helm进行升级 - 或者,使用
kubectl编辑NDM configmap,更新过滤器
- 使用
落地实践
OpenEBS的cStor与Jiva引擎由于组件过多,配置相较其他存储方案繁琐,生产环境不建议使用,这里我们仅论述Local PV引擎。
Local PV引擎不具备存储级复制能力,适用于k8s有状态服务的后端存储(如: es、redis等)
Local PV Hostpath实践
对比Kubernetes Hostpath卷相比,OpenEBS本地PV Hostpath卷具有以下优势:
OpenEBS本地PV Hostpath允许您的应用程序通过StorageClass、PVC和PV访问Hostpath。 这为您提供了更改PV提供者的灵活性,而无需重新设计应用程序YAML使用
Velero备份和恢复进行数据保护通过对应用程序
YAML和pod完全屏蔽主机路径来防范主机路径安全漏洞
环境依赖:
k8s 1.12以上OpenEBS 1.0以上
实践环境:
docker 19.03.8k8s 1.18.6CentOS7
[root@localhost ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
node1 Ready master,worker 8m8s v1.18.6
node2 Ready master,worker 7m15s v1.18.6
node3 Ready master,worker 7m15s v1.18.6
创建数据目录
在将要创建Local PV Hostpaths的节点上设置目录。这个目录将被称为BasePath。默认位置是/var/openebs/local
节点node1、node2、node3创建/data/openebs/local目录
(/data可以预先挂载数据盘,如未挂载额外数据盘,则使用操作系统'/'挂载点存储空间)
mkdir -p /data/openebs/local
下载应用描述文件
发布
openebs应用
根据上述配置文件,保证k8s集群可访问到如下镜像(建议导入本地私有镜像库,如: harbor)
openebs/node-disk-manager:1.5.0
openebs/node-disk-operator:1.5.0
openebs/provisioner-localpv:2.10.0
更新openebs-operator.yaml中镜像tag为实际tag
image: openebs/node-disk-manager:1.5.0
image: openebs/node-disk-operator:1.5.0
image: openebs/provisioner-localpv:2.10.0
发布
kubectl apply -f openebs-operator.yaml
查看发布状态
[root@localhost openebs]# kubectl get pod -n openebs -w
NAME READY STATUS RESTARTS AGE
openebs-localpv-provisioner-6d6d9cfc99-4sltp 1/1 Running 0 10s
openebs-ndm-85rng 1/1 Running 0 10s
openebs-ndm-operator-7df6668998-ptnlq 0/1 Running 0 10s
openebs-ndm-qgqm9 1/1 Running 0 10s
openebs-ndm-zz7ps 1/1 Running 0 10s
创建存储类
更改配置文件中的内容
value: "/var/openebs/local/"
发布创建存储类
cat > openebs-hostpath-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: openebs-hostpath
annotations:
openebs.io/cas-type: local
cas.openebs.io/config: |
#hostpath type will create a PV by
# creating a sub-directory under the
# BASEPATH provided below.
- name: StorageType
value: "hostpath"
#Specify the location (directory) where
# where PV(volume) data will be saved.
# A sub-directory with pv-name will be
# created. When the volume is deleted,
# the PV sub-directory will be deleted.
#Default value is /var/openebs/local
- name: BasePath
value: "/data/openebs/local/"
provisioner: openebs.io/local
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
EOF
kubectl apply -f openebs-hostpath-sc.yaml
创建
pvc验证可用性
cat > local-hostpath-pvc.yaml <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: local-hostpath-pvc
spec:
storageClassName: openebs-hostpath
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5G
EOF
kubectl apply -f local-hostpath-pvc.yaml
查看pvc状态
[root@localhost openebs]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
local-hostpath-pvc Pending openebs-hostpath 2m15s
输出显示STATUS为Pending。这意味着PVC还没有被应用程序使用。
创建
pod
cat > local-hostpath-pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: hello-local-hostpath-pod
spec:
volumes:
- name: local-storage
persistentVolumeClaim:
claimName: local-hostpath-pvc
containers:
- name: hello-container
image: busybox
command:
- sh
- -c
- 'while true; do echo "`date` [`hostname`] Hello from OpenEBS Local PV." >> /mnt/store/greet.txt; sleep $(($RANDOM % 5 + 300)); done'
volumeMounts:
- mountPath: /mnt/store
name: local-storage
EOF
发布创建
kubectl apply -f local-hostpath-pod.yaml
验证数据是否写入卷
[root@localhost openebs]# kubectl exec hello-local-hostpath-pod -- cat /mnt/store/greet.txt
Thu Jun 24 15:10:45 CST 2021 [node1] Hello from OpenEBS Local PV.
验证容器是否使用
Local PV Hostpath卷
[root@localhost openebs]# kubectl describe pod hello-local-hostpath-pod
Name: hello-local-hostpath-pod
Namespace: default
Priority: 0
...
Volumes:
local-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: local-hostpath-pvc
ReadOnly: false
default-token-98scc:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-98scc
Optional: false
...
查看
pvc状态
[root@localhost openebs]# kubectl get pvc local-hostpath-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
local-hostpath-pvc Bound pvc-6eac3773-49ef-47af-a475-acb57ed15cf6 5G RWO openebs-hostpath 10m
查看该
pv卷数据存储目录为
[root@localhost openebs]# kubectl get -o yaml pv pvc-6eac3773-49ef-47af-a475-acb57ed15cf6|grep 'path:'
f:path: {}
path: /data/openebs/local/pvc-6eac3773-49ef-47af-a475-acb57ed15cf6
并且pv配置了亲和性,制定了调度节点为node2
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 5G
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: local-hostpath-pvc
namespace: default
resourceVersion: "9034"
uid: 6eac3773-49ef-47af-a475-acb57ed15cf6
local:
fsType: ""
path: /data/openebs/local/pvc-6eac3773-49ef-47af-a475-acb57ed15cf6
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node2
persistentVolumeReclaimPolicy: Delete
storageClassName: openebs-hostpath
volumeMode: Filesystem
验证三个节点存储目录下

结果证明数据仅存在于node2下
清理
pod
kubectl delete pod hello-local-hostpath-pod
基准测试
调整以下内容
image: openebs/perf-test:latest # 调整为内网镜像库tag
claimName: dbench # 调整为local-hostpath-pvc
发布运行
kubectl create -f fio-deploy.yaml
查看运行状态
[root@node1 openebs]# kubectl get pod
NAME READY STATUS RESTARTS AGE
dbench-729cw-nqfpt 1/1 Running 0 24s
查看基准测试结果
[root@node1 openebs]# kubectl logs -f dbench-729cw-nqfpt
...
All tests complete.
==================
= Dbench Summary =
==================
Random Read/Write IOPS: 2144/6654. BW: 131MiB/s / 403MiB/s
Average Latency (usec) Read/Write: 4254.08/3661.59
Sequential Read/Write: 1294MiB/s / 157MiB/s
Mixed Random Read/Write IOPS: 1350/443
清理
kubectl delete pvc local-hostpath-pvc
kubectl delete sc openebs-hostpath
Local PV Device实践
对比Kubernetes本地持久卷,OpenEBS本地PV设备卷有以下优点:
OpenEBS本地PV设备卷provider是动态的,Kubernetes设备卷provider是静态的OpenEBS NDM更好地管理用于创建本地pv的块设备。NDM提供了发现块设备属性、设置设备筛选器、度量集合以及检测块设备是否已经跨节点移动等功能
环境依赖:
k8s 1.12以上OpenEBS 1.0以上
实践环境:
docker 19.03.8k8s 1.18.6CentOS7
[root@localhost ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
node1 Ready master,worker 8m8s v1.18.6
node2 Ready master,worker 7m15s v1.18.6
node3 Ready master,worker 7m15s v1.18.6
三个节点上的/dev/sdb作为块设备存储
[root@node1 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part
└─centos-root 253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.4G 0 rom
[root@node2 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part
└─centos-root 253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.4G 0 rom
[root@node3 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part
└─centos-root 253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.4G 0 rom
创建数据目录
在将要创建Local PV Hostpaths的节点上设置目录。这个目录将被称为BasePath。默认位置是/var/openebs/local
节点node1、node2、node3创建/data/openebs/local目录
(/data可以预先挂载数据盘,如未挂载额外数据盘,则使用操作系统'/'挂载点存储空间)
mkdir -p /data/openebs/local
下载应用描述文件
发布
openebs应用
根据上述配置文件,保证k8s集群可访问到如下镜像(建议导入本地私有镜像库,如: harbor)
openebs/node-disk-manager:1.5.0
openebs/node-disk-operator:1.5.0
openebs/provisioner-localpv:2.10.0
更新openebs-operator.yaml中镜像tag为实际tag
image: openebs/node-disk-manager:1.5.0
image: openebs/node-disk-operator:1.5.0
image: openebs/provisioner-localpv:2.10.0
发布
kubectl apply -f openebs-operator.yaml
查看发布状态
[root@localhost openebs]# kubectl get pod -n openebs -w
NAME READY STATUS RESTARTS AGE
openebs-localpv-provisioner-6d6d9cfc99-4sltp 1/1 Running 0 10s
openebs-ndm-85rng 1/1 Running 0 10s
openebs-ndm-operator-7df6668998-ptnlq 0/1 Running 0 10s
openebs-ndm-qgqm9 1/1 Running 0 10s
openebs-ndm-zz7ps 1/1 Running 0 10s
创建存储类
cat > local-device-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-device
annotations:
openebs.io/cas-type: local
cas.openebs.io/config: |
- name: StorageType
value: device
provisioner: openebs.io/local
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
EOF
kubectl apply -f local-device-sc.yaml
创建
pod及pvc
cat > local-device-pod.yaml <<EOF
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: local-device-pvc
spec:
storageClassName: local-device
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5G
---
apiVersion: v1
kind: Pod
metadata:
name: hello-local-device-pod
spec:
volumes:
- name: local-storage
persistentVolumeClaim:
claimName: local-device-pvc
containers:
- name: hello-container
image: busybox
command:
- sh
- -c
- 'while true; do echo "`date` [`hostname`] Hello from OpenEBS Local PV." >> /mnt/store/greet.txt; sleep $(($RANDOM % 5 + 300)); done'
volumeMounts:
- mountPath: /mnt/store
name: local-storage
EOF
发布
kubectl apply -f local-device-pod.yaml
查看pod状态
[root@node1 openebs]# kubectl get pod hello-local-device-pod -w
NAME READY STATUS RESTARTS AGE
hello-local-device-pod 1/1 Running 0 9s
确认pod关联pvc是否为local-device-pvc
[root@node1 openebs]# kubectl describe pod hello-local-device-pod
Name: hello-local-device-pod
Namespace: default
Node: node2/192.168.1.112
...
Volumes:
local-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: local-device-pvc
ReadOnly: false
...
观察到调度的节点为node2,确认node2节点/dev/sdb是否被使用
[root@node2 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part
└─centos-root 253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.4G 0 rom
[root@node2 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 400G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 399G 0 part
└─centos-root
253:0 0 399G 0 lvm /
sdb 8:16 0 20G 0 disk /var/lib/kubelet/pods/266b7b14-5eb7-40ec-bccb-3ac189acf939/volumes/kubernetes.io~local-volume/pvc-9bd89019-13dc-4
sr0 11:0 1 4.4G 0 rom
确实被使用,OpenEBS强大之处则在于此,极致的简洁。
如上文我们讨论的那样,NDM负责发现块设备并过滤掉不应该被OpenEBS使用的设备,例如,检测有OS文件系统的磁盘。
基准测试
创建基准测试pvc
cat > dbench-pvc.yaml <<EOF
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: dbench
spec:
storageClassName: local-device
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5G
EOF
调整以下内容
image: openebs/perf-test:latest # 调整为内网镜像库tag
发布运行
kubectl create -f dbench-pvc.yaml
kubectl create -f fio-deploy.yaml
查看运行状态
[root@node1 openebs]# kubectl get pod
NAME READY STATUS RESTARTS AGE
dbench-vqk68-f9877 1/1 Running 0 24s
查看基准测试结果
[root@node1 openebs]# kubectl logs -f dbench-vqk68-f9877
...
All tests complete.
==================
= Dbench Summary =
==================
Random Read/Write IOPS: 3482/6450. BW: 336MiB/s / 1017MiB/s
Average Latency (usec) Read/Write: 2305.77/1508.63
Sequential Read/Write: 6683MiB/s / 2312MiB/s
Mixed Random Read/Write IOPS: 3496/1171
从结果来看,相较Local PV HostPath模式性能翻倍
总结
在整个测试验证过程,OpenEBS给我的感觉是:极简的操作,尤其Local PV引擎的部署使用。
但OpenEBS现阶段也存在一些不足:
cStor与Jiva数据面组件较多,配置较为繁琐(第一感觉概念性的组件过多,)cStor与Jiva部分组件创建依赖内部定义的镜像tag,在离线环境下无法通过调整为私有库tag导致组件无法成功运行- 存储类型单一,多个引擎仅支持块存储类型,不支持原生多节点读写(需结合
NFS实现),对比ceph等稍显逊色
建议以下场景使用OpenEBS作为后端存储:
- 单机测试环境
- 多机实验/演示环境