跳转到主要内容

OpenEBS Jiva 复制卷部署笔记

OpenEBS 管理每个 Kubernetes 节点上可用的存储,并使用该存储为有状态工作负载提供本地或分布式(也称为复制)持久卷。

如果是本地卷:

  • OpenEBS 可以使用原始块设备或分区,或使用主机路径上的子目录,或使用 LVM、ZFS 或稀疏文件来创建持久卷。
  • 本地卷直接安装到 Stateful Pod 中,数据路径中没有来自 OpenEBS 的任何额外开销,从而减少了延迟。
  • OpenEBS 为本地卷提供了额外的工具,用于监控、备份/恢复、灾难恢复、ZFS 或 LVM 支持的快照、基于容量的调度等。

在分布式(又名复制)卷的情况下:

  • OpenEBS 使用其引擎之一(Mayastor、cStor 或 Jiva)为每个分布式持久卷创建微服务。
  • Stateful Pod 将数据写入 OpenEBS 引擎,这些引擎将数据同步复制到集群中的多个节点。OpenEBS 引擎本身部署为 pod,由 Kubernetes 编排。当运行有状态 pod 的节点发生故障时,该 pod 将被重新调度到集群中的另一个节点,OpenEBS 使用其他节点上的可用数据副本提供对数据的访问。
  • Stateful Pod 使用 iSCSI(cStor 和 Jiva)或 NVMeoF(Mayastor)连接到 OpenEBS 分布式持久卷。
  • OpenEBS cStor 和 Jiva 专注于存储的易用性和耐用性。这些引擎分别使用定制版本的 ZFS 和 Longhorn 技术将数据写入存储。
  • OpenEBS Mayastor 是最新的引擎,以耐用性和性能为设计目标而开发;OpenEBS Mayastor 有效地管理计算(hugepages、内核)和存储(NVMe 驱动器)以提供快速的分布式块存储。


OpenEBS 贡献者更喜欢将分布式块存储卷称为复制卷,以避免与传统的分布式块存储混淆,原因如下:

  • 分布式块存储倾向于将卷的数据块分片到集群中的多个节点上。复制卷将卷的所有数据块保存在节点上,并且为了持久性将整个数据复制到集群中的其他节点。
  • 在访问卷数据时,分布式块存储依赖于元数据哈希算法来定位块所在的节点,而复制卷可以从任何持久保存数据的节点(也称为副本节点)访问数据。
  • 与传统的分布式块存储相比,复制卷的爆炸半径更小。
  • 复制卷专为云原生有状态工作负载而设计,这些工作负载需要大量容量的卷,这些容量通常可以从单个节点提供服务,而不是数据在集群中的多个节点之间分片的单个大卷。
  • 复制卷是将其数据同步复制到多个节点的卷。复制卷可以承受节点故障。还可以跨可用性区域设置复制,帮助应用程序跨可用性区域移动。

以上内容机器翻译自官方文档


对于我的需求来说,一个 OpenEBS 复制卷能够将数据同时储存至多个节点、满足了高可用需求。
复制卷可以从任何持久保存数据的节点访问数据,满足了同步需求。
然后由 OpenEBS 提供储存类给容器使用。
(发现 Longhorn 也不错,跑去用 Longhorn 了)


储存引擎

OpenEBS 有三种储存引擎,不同的引擎能提供不同的功能。

超链接内有详细介绍。

除了这三种引擎,还有 Local PV,不太算存储引擎。
Local PV 意味着存储只能从单个节点使用。Local PV 表示已挂载的本地存储设备,例如磁盘、分区或目录。


以下表格部分摘自 https://zhuanlan.zhihu.com/p/519172233

特性 Jiva cStor Local PV Mayastor
轻量级运行于用户空间 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
应用需求 存储类型 OpenEBS 卷类型
低时延、高可用性、同步复制、快照、克隆、精简配置 未格式化的块设备
(SSD/HDD/云硬盘)
OpenEBS Mayastor
高可用性、同步复制、快照、克隆、精简配置 未格式化的块设备
(SSD/HDD/云硬盘)
OpenEBS cStor
高可用性、同步复制、精简配置 主机路径或外部挂载存储 OpenEBS Jiva
低时延、本地 PV 主机路径或外部挂载存储 Dynamic Local PV - Hostpath, Dynamic Local PV - Rawfile
低时延、本地 PV 未格式化的块设备
(SSD/HDD/云硬盘)
Dynamic Local PV - Device
低延迟,本地 PV,快照,克隆 未格式化的块设备
(SSD/HDD/云硬盘)
OpenEBS Dynamic Local PV - ZFS , OpenEBS Dynamic Local PV - LVM


对于我的需求来说,Jiva 可以直接使用主机上的已有路径,而其他两个则需要使用空的块设备。
我不需要非常高性能的储存,添加新硬盘也不是想就能有的,所以选择 Jiva 是不错的选择。


先决条件
  • Kubernetes 1.18 或更高版本;
  • 所有工作节点安装并运行 iscsi-initiator-utils 或 open-iscsi;
  • 有权将 RBAC 组件安装到 kube-system 命名空间中;
  • OpenEBS localpv-hostpath 2.6.0 或更高版本;


安装 iSCSI initiator utils

RHEL/CentOS 系列

在所有工作节点执行:

sudo yum install iscsi-initiator-utils
sudo systemctl enable --now iscsid
modprobe iscsi_tcp
echo iscsi_tcp >/etc/modules-load.d/iscsi-tcp.conf



通过 Helm 安装

添加源:

helm repo add openebs https://openebs.github.io/charts
helm repo update

如果你访问 github 困难,可以试试  https://github.com/ineo6/hosts

官方文档不太对,不建议使用默认值安装。

使用 CSI 驱动程序安装 Jiva:

helm install openebs openebs/openebs --namespace openebs --create-namespace \
--set legacy.enabled=false \
--set jiva.enabled=true \
--set openebs-ndm.enabled=true \
--set localpv-provisioner.enabled=true \
--set jiva.defaultStoragePath=/var/openebs \
--set image.repository=k8s-gcr.m.daocloud.io
  • legacy.enabled=false 禁用旧的 out-of-tree 树外组件;
  • jiva.enabled=true 启用 Jiva;
  • openebs-ndm.enabled=true 启用 ndm;
  • localpv-provisioner.enabled=true 启用Local PV provisioner;
  • jiva.defaultStoragePath=<储存路径> 自定义 Jiva 储存目录,默认 /var/openebs;
  • image.repository=<源地址> 自定义源地址,默认为 k8s.gcr.io,此处设置为 Daocloud 镜像;

此命令会在 openebs 命名空间内安装 OpenEBS Jiva 和 Local PV 组件。
更多信息请参阅 https://github.com/openebs/charts/tree/master/charts/openebs


验证 OpenEBS 安装

验证 pod

使用 kubectl get pods -n openebs -o wide 你应该能看到有以下几种 pod 正在全数正常运行。  

openebs-jiva-csi-controller-0 
openebs-jiva-csi-node
openebs-jiva-operator
openebs-localpv-provisioner
openebs-ndm-operator
openebs-ndm

如果一直 ContainerCreating,大概率是镜像问题。
安装时别忘了设置镜像,默认的 k8s.gcr.io 大陆无法访问。

验证储存类

使用 kubectl get sc 你应该能看到一下几种 StorageClasses

NAME                       PROVISIONER           RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
openebs-device             openebs.io/local      Delete          WaitForFirstConsumer   false                  5m15s
openebs-hostpath           openebs.io/local      Delete          WaitForFirstConsumer   false                  5m15s
openebs-jiva-csi-default   jiva.csi.openebs.io   Delete          Immediate              true                   5m15s
  • openebs-jiva-csi-default 用于配置 jiva 卷,此类默认就会复制;
  • openebs-hostpath 用于在主机路径上配置本地 PV,不会复制;
  • openebs-device 用于在设备上配置本地 PV,不会复制;

至此就已安装完毕了,然后你就可以创建 PVC 什么的了。
更多信息请参考 https://openebs.io/blog/provisioning-openebs-jiva-volumes-via-csi


简单测试

创建一个 PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: example-jiva-csi-pvc
spec:
  storageClassName: openebs-jiva-csi-default
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi

在储存类 openebs-jiva-csi-default 内创建一个 4GiB 的 PVC。
保存到 <文件名>.yaml 中,然后 kubectl apply -f <文件名>.yaml 即可。

然后 kubectl get pvc 应该就能看见此 PVC。

NAME                   STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS               AGE
example-jiva-csi-pvc   Bound     pvc-2d9ae46f-c38f-4aef-af33-e82eec7af2b5   4Gi        RWO            openebs-jiva-csi-default   10s

再查看一下状态:kubectl get jivavolume  pvc-2d9ae46f-c38f-4aef-af33-e82eec7af2b5 -n openebs

然后就可以用这个 PVC 了。
更多信息请参阅:https://openebs.io/blog/provisioning-openebs-jiva-volumes-via-csi


卷策略

如果你不想用默认的卷复制策略,或是需要调整资源限制、容忍读、节点选择器等,你可以创建 JivaVolumePolicy(JVP)。
例如:

apiVersion: openebs.io/v1alpha1
kind: JivaVolumePolicy
metadata:
  name: example-jivavolumepolicy
  namespace: openebs
spec:
  replicaSC: openebs-hostpath
  target:
    # This sets the number of replicas for high-availability
    # replication factor <= no. of (CSI) nodes
    replicationFactor: 3
    # disableMonitor: false
    # auxResources:
    # tolerations:
    # resources:
    # affinity:
    # nodeSelector:
    # priorityClassName:
  # replica:
    # tolerations:
    # resources:
    # affinity:
    # nodeSelector:
    # priorityClassName:

然后使用 JVP 创建新的储存类:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: openebs-jiva-csi-sc
provisioner: jiva.csi.openebs.io
allowVolumeExpansion: true
parameters:
  cas-type: "jiva"
  policy: "example-jivavolumepolicy"

更多信息请参阅:https://github.com/openebs/jiva-operator/blob/master/docs/tutorials/policies.md



小知识

什么是 In-Tree 树内、Out-Of-Tree 树外、CSI (Container Storage Interface) 容器存储接口

早期 Kubernetes 处理问题比较粗暴,有什么需求就直接写死在里面,比如 Ceph 接口。这叫就做 In-Tree 树内
时间一长各种各样的接口想要加进来,这么耦合肯定是不行的。

于是另一种方案就来了,就是做成外置插件 external provisioner,这叫就做 Out-Of-Tree 树外
但这只是个 provisioner 能实现的功能有限。

最后解决方案当然就是制定一个标准规范,大家自己按照规范做个插件即可,这个规范就叫做 CSI (Container Storage Interface) 容器存储接口


OpenEBS 和 Longhorn 是什么关系

OpenEBS 最初是作为 Longhorn Engine 的一个分支开始的。
然而,OpenEBS Jiva 和 Longhorn 在以下方面存在一些分歧,于是就独立出来了。

  • Control Plane functionality
  • iSCSI Target implementation
  • Quorum
  • Backup / Restore
  • UI

你可以在这找到旧的仓库 https://github.com/openebs/longhorn



主要参考