piraeus简介
Piraeus 是面向 Kubernetes 的高性能、高可用性、简单、安全且与云无关的云原生存储解决方案,号称性能和稳定性都优于 Ceph/OpenEBS/Longhorn 等项目。Piraeus 对应的商业产品为LINSTOR 。
Piraeus 项目成长路径:
- 2019 年 5 月由浦发银行、DaoCloud 道客联合奥地利 LINBIT 公司共同孵化,致力于为 Kubernetes
的本地持久卷实现全局管理,动态分配,高可用,和压缩备份等企业级功能。 - 2020 年 7 月在 KuberCon China 被首次分享。
- 2021 年 1 月通过 CNCF TOC 投票入选云原生计算基金会(CNCF)Sandbox 项目。
- 2021 年 5 月注册成为LF/CNCF 资产,并在 2021 年7 月世界人工智能大会上正式宣布被 CNCF 接纳为沙盒项目。
官方网站:https://piraeus.io/
项目地址:https://github.com/piraeusdatastore/piraeus
Piraeus核心技术为基于操作系统内核的DRBD数据块复制技术来实现本地卷可高用。
Piraeus Datastore 在数据平面使用著名的 Distributed Replicated Block Device (以下简称 DRBD )开源技术。DRBD 是 Linux 里的块设备跨主机复制软件,由奥地利工程师 Philipp Reisner 于 2000 年创立。2009 年 Linus Torvalds 亲自审核 DRBD 技术,并将其整合到 Linux 内核中作为 Linux 的标准组件之一。
之后,DRBD 不断演进和完善,在企业级的关键业务中得到了广泛的应用和大量的验证,成为 Linux 开源社区里最成熟的块数据同步技术。2019 年 11 月 18 日,在美国圣地亚哥的 KubeCon 大会上,Piraeus Datastore 正式发布。
左四(Philipp Reisner)
Piraeus 项目能够具备高可用,高性能,丰富的企业级存储特性,有以下原因:
- 复用成熟的 Linux 内核 Distributed Replicated Block Device (分布式复制块,简称 DRBD) 数据技术,没有新写的数据层
- 邀请 DRBD 作者 Phil Reisner 亲自督导
- 控制流和数据流完全分离
- 100% 开源, Apache 开源许可,支持商业开发
- DaoCloud 道客 和 LINBIT 合作提供企业级技术支持
- 性能和稳定性都优于
Ceph/OpenEBS/Longhorn
等项目
Piraeus 与其他存储对比
Piraeus vs. 专业NAS
特点 | Piraeus | NAS |
---|---|---|
动态分配 | 有 | 无 |
数据隔离 | 块级别 | 无 (都在一个母路径下) |
OLTP数据库小IO性能 | 优 | 慢 |
本地数据访问 | 有 | 无 |
易用性 | K8S集群内即插即用 | 购买专业NAS设备 |
成本 | 低 | 高 |
延展度 | 高(和k8s节点数匹配) | 低 |
Piraeus vs. 本地盘
特点 | Piraeus | 本地盘 |
---|---|---|
动态分配 | 有 | 无 |
数据多节点高可用 | 有 | 单点故障 |
数据远程访问 | 有 | 无 |
数据隔离 | 块级别 | 无 (都在一个母路径下) |
安全性 | 优 | 差(暴露OS路径给租户) |
容量管理 | 有 | 无 |
超量分配(thin) | 有 | 无 |
快照克隆 | 有 | 无 |
压缩去冗 | 有 | 无 |
和同类别项目对比
存储技术 | 数据技术 | 数据同步技术 | 开源 | 商业许可 |
---|---|---|---|---|
Piraeus | LVM, Zvol | Linux 内核原生 DRBD 技术 | 开源 | 自主掌控 和代码作者合作 |
Longhorn | Sparse file | 自研未知 | 开源 | 属于 Rancher |
Rook(ceph) | Sparse file | Ceph | 开源 | 属于 Redhat |
Portworx | Btrfs | 商业自研 | 纯商业 | 属于 PureStorage |
Piraeus 案例
博客链接:https://piraeus.io/site/blog/
传统的大数据平台是一种保存大量数据并对其进行流式计算的基础设施。典型的大数据平台包括Hadoop、Spark、Flume、Flink、Kafka等组件。这些组件的容器化和编排催生了云原生大数据平台。
在研究了Cloudera CDP等主流大数据平台,充分了解采用云原生工作流程的优势和挑战后,浦发银行认识到存储技术是云原生大数据平台建设成功的关键。为此,浦发银行与合作伙伴合作开展云原生存储项目Piraeus Datastore的研究和实验,最终浦发银行的工程师采用了Piraeus云原生存储,并将其应用到大数据生产中。
Piraeus 数据卷是块设备,使用 ext4 或 xfs 文件系统本地安装。Piraeus Kubernetes-CSI 驱动程序和 DRBD Transport 远程挂载技术使容器能够从集群中的任何节点访问数据卷。Piraeus多副本卷采用DRBD同步复制技术,在保证高可用性的同时,提供堪比本地磁盘的高吞吐量和低延迟。
在成功使用 Piraeus 支持节点管理器后,还配置了 MySQL 容器来挂载 Piraeus 副本卷,这也取得了非常令人满意的结果。
piraeus-operator部署
项目地址:https://github.com/piraeusdatastore/piraeus-operator
准备1至多个kubernetes节点,这里以3个节点为例,测试场景下节点无需挂盘等额外任何操作。
root@node1:~# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node1 Ready control-plane 7d4h v1.26.7 192.168.72.30 <none> Ubuntu 22.04.2 LTS 5.15.0-78-generic containerd://1.6.22
node2 Ready control-plane 7d4h v1.26.7 192.168.72.31 <none> Ubuntu 22.04.2 LTS 5.15.0-78-generic containerd://1.6.22
node3 Ready control-plane 7d4h v1.26.7 192.168.72.32 <none> Ubuntu 22.04.2 LTS 5.15.0-78-generic containerd://1.6.22
所有节点配置内核参数
下载helm chart
wget https://github.com/piraeusdatastore/piraeus-operator/archive/refs/tags/v2.1.1.tar.gz
tar -zxvf v2.1.1.tar.gz
cd piraeus-operator-2.1.1/charts/
使用helm安装piraeus-operator
helm upgrade --install piraeus-operator ./piraeus \
--create-namespace -n piraeus-datastore \
--set installCRDs=true
查看部署的pods
root@node1:~# kubectl -n piraeus-datastore get pods
NAME READY STATUS RESTARTS AGE
piraeus-datastore-controller-manager-6f6b8f48c4-st7zb 2/2 Running 0 14m
部署Piraeus数据存储
创建storage cluster
$ kubectl apply -f - <<EOF
apiVersion: piraeus.io/v1
kind: LinstorCluster
metadata:
name: linstorcluster
spec: {}
EOF
查看部署的pods
root@node1:~# kubectl -n piraeus-datastore get pods
NAME READY STATUS RESTARTS AGE
ha-controller-bmz2w 1/1 Running 0 66s
ha-controller-rn54t 1/1 Running 0 66s
ha-controller-x6sh9 1/1 Running 0 66s
linstor-controller-97cd7495c-rqgzd 1/1 Running 0 67s
linstor-csi-controller-7f85967cd9-8dq7t 7/7 Running 0 67s
linstor-csi-node-dxpc4 3/3 Running 0 67s
linstor-csi-node-p9f62 3/3 Running 0 67s
linstor-csi-node-q8dwv 3/3 Running 0 67s
node1 2/2 Running 0 59s
node2 2/2 Running 0 66s
node3 2/2 Running 0 65s
piraeus-operator-controller-manager-6f8974c495-fk5ql 2/2 Running 0 2m2s
使用linstor
客户端检查已部署的 LINSTOR集群的状态:
root@node1:~# kubectl -n piraeus-datastore exec deploy/linstor-controller -- linstor node list
+--------------------------------------------------------+
| Node | NodeType | Addresses | State |
|========================================================|
| node1 | SATELLITE | 100.64.0.82:3366 (PLAIN) | Online |
| node2 | SATELLITE | 100.64.1.173:3366 (PLAIN) | Online |
| node3 | SATELLITE | 100.64.2.178:3366 (PLAIN) | Online |
+--------------------------------------------------------+
配置存储
我们尚未为卷配置任何存储位置。这可以通过创建LinstorSatelliteConfiguration
新资源来完成 。
查看支持的存储池类型:
kubectl explain linstorsatelliteconfigurations.spec.storagePools
支持的存储池类型如下
filePool
配置基于文件系统的存储池,为每个卷分配一个常规文件fileThinPool
配置基于文件系统的存储池,为每个卷分配稀疏文件lvmPool
将LVM卷组配置为存储池lvmThinPool
将LVM精简池配置为存储池。
我们将在每个节点上创建一个fileThinPool
type 的存储池。我们选择fileThinPool
它是因为它不需要在主机上进行进一步配置,直接使用根磁盘路径,无需额外准备磁盘。
$ kubectl apply -f - <<EOF
apiVersion: piraeus.io/v1
kind: LinstorSatelliteConfiguration
metadata:
name: storage-pool
spec:
storagePools:
- name: pool1
fileThinPool:
directory: /var/lib/piraeus-datastore/pool1
EOF
这将导致一些 Pod 被重新创建。发生这种情况时linstor node list
会暂时显示节点离线,再等一会儿,节点又会出现Online
。一旦节点再次连接,我们就可以验证存储池是否已配置:
root@node1:~# kubectl -n piraeus-datastore exec deploy/linstor-controller -- linstor storage-pool list
+------------------------------------------------------------------------------------------------------------------------------------------------+
| StoragePool | Node | Driver | PoolName | FreeCapacity | TotalCapacity | CanSnapshots | State | SharedName |
|================================================================================================================================================|
| DfltDisklessStorPool | node1 | DISKLESS | | | | False | Ok | |
| DfltDisklessStorPool | node2 | DISKLESS | | | | False | Ok | |
| DfltDisklessStorPool | node3 | DISKLESS | | | | False | Ok | |
| pool1 | node1 | FILE_THIN | /var/lib/piraeus-datastore/pool1 | 23.17 GiB | 96.90 GiB | True | Ok | |
| pool1 | node2 | FILE_THIN | /var/lib/piraeus-datastore/pool1 | 72.38 GiB | 96.90 GiB | True | Ok | |
| pool1 | node3 | FILE_THIN | /var/lib/piraeus-datastore/pool1 | 70.57 GiB | 96.90 GiB | True | Ok | |
+------------------------------------------------------------------------------------------------------------------------------------------------+
使用Piraeus Datastore
支持的所有参数:https://linbit.com/drbd-user-guide/linstor-guide-1_0-en/#s-kubernetes-sc-parameters
我们现在已经成功部署和配置了 Piraeus 数据存储,并准备 PersistentVolume在 Kubernetes 中创建我们的第一个数据存储。
首先,我们将为我们的卷设置一个新的StorageClass。在StorageClass
中,我们指定上面的存储池:
$ kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: piraeus-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: linstor.csi.linbit.com
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
linstor.csi.linbit.com/placementCount: "2"
linstor.csi.linbit.com/storagePool: pool1
csi.storage.k8s.io/fstype: xfs
EOF
参数说明:
- placementCount: 支持1/2/3副本,默认为1
- fstype:支持ext4和xfs,默认为ext4
查看创建的storageclass
root@node1:~# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
piraeus-storage (default) linstor.csi.linbit.com Delete WaitForFirstConsumer true 16s
接下来,我们将创建一个PersistentVolumeClaim,从新创建的StorageClass
中请求 1G 的存储空间。
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-volume
spec:
storageClassName: piraeus-storage
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
EOF
当我们检查创建的 PersistentVolumeClaim 时,我们可以看到它仍然处于Pending
状态。
$ kubectl get persistentvolumeclaim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-volume Pending piraeus-storage 14s
首先需要创建一个“消费者”,在本例中只是一个Pod
. 对于我们的消费者,我们将为一个简单的 Web 服务器创建一个部署,从我们的卷中提供文件。
注意:piraeus仅支持 strategy.type: Recreate
策略。
$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: volume-logger
spec:
selector:
matchLabels:
app.kubernetes.io/name: volume-logger
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: volume-logger
spec:
terminationGracePeriodSeconds: 0
containers:
- name: volume-logger
image: busybox
args:
- sh
- -c
- |
echo "Hello from \$HOSTNAME, running on \$NODENAME, started at \$(date)" >> /volume/hello
# We use this to keep the Pod running
tail -f /dev/null
env:
- name: NODENAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- mountPath: /volume
name: data-volume
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-volume
EOF
短暂等待后,Pod 已完成Running
,我们的PersistentVolumeClaim
现在已完成Bound
:
root@node1:~# kubectl wait pod --for=condition=Ready -l app.kubernetes.io/name=volume-logger
pod/volume-logger-cbcd897b7-tm8rr condition met
root@node1:~# kubectl get persistentvolumeclaim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-volume Bound pvc-9599f79e-d825-4550-b044-5c577f1f0020 1Gi RWO piraeus-storage 112s
root@node1:~# kubectl -n piraeus-datastore exec deploy/linstor-controller -- linstor resource list-volumes
+---------------------------------------------------------------------------------------------------------------------------------------------+
| Node | Resource | StoragePool | VolNr | MinorNr | DeviceName | Allocated | InUse | State |
|=============================================================================================================================================|
| node1 | pvc-9599f79e-d825-4550-b044-5c577f1f0020 | pool1 | 0 | 1004 | /dev/drbd1004 | 32.91 MiB | InUse | UpToDate |
| node2 | pvc-9599f79e-d825-4550-b044-5c577f1f0020 | pool1 | 0 | 1004 | /dev/drbd1004 | 932 KiB | Unused | UpToDate |
| node3 | pvc-9599f79e-d825-4550-b044-5c577f1f0020 | DfltDisklessStorPool | 0 | 1004 | /dev/drbd1004 | | Unused | TieBreaker |
+---------------------------------------------------------------------------------------------------------------------------------------------+
通过在 Pod 中读取来检查我们的 Pod 是否实际记录了预期的信息:
root@node1:~# kubectl exec deploy/volume-logger -- cat /volume/hello
Hello from volume-logger-cbcd897b7-tm8rr, running on node1, started at Thu Aug 10 08:21:06 UTC 2023
测试复制
现在将验证将 Pod 移动到另一个节点时,我们仍然可以访问相同的数据。
为了测试这一点,将禁用 Pod 当前运行的节点上的调度。一旦我们触发重启,这就会迫使 Kubernetes 将 Pod 移动到另一个节点。在本示例中,Hello 消息告诉我们 Pod 是在 node1 上启动的,因此这是我们禁用的节点。将名称替换为您自己的节点名称。
root@node1:~# kubectl cordon node1
node/node1 cordoned
现在,以触发新的部署。由于禁用了node1节点调度,另一个节点将不得不接管 Pod。
root@node1:~# kubectl rollout restart deploy/volume-logger
deployment.apps/volume-logger restarted
root@node1:~# kubectl wait pod --for=condition=Ready -l app.kubernetes.io/name=volume-logger
pod/volume-logger-649f8df755-v5km9 condition met
root@node1:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-logger-649f8df755-v5km9 1/1 Running 0 45s 100.64.2.240 node3 <none> <none>
正如预期的那样,Pod 现在在不同的节点上运行,在本例中是在node3.
现在,可以验证来自原始 pod 的消息是否仍然存在:
root@node1:~# kubectl exec deploy/volume-logger -- cat /volume/hello
Hello from volume-logger-cbcd897b7-tm8rr, running on node1, started at Thu Aug 10 08:21:06 UTC 2023
Hello from volume-logger-649f8df755-v5km9, running on node3, started at Thu Aug 10 08:26:56 UTC 2023
正如预期的那样,仍然可以看到来自 node1 的消息,以及来自 node2 上新 Pod 的消息。
还可以看到 LINSTOR 现在显示新节点上的InUse卷:
root@node1:~# kubectl -n piraeus-datastore exec deploy/linstor-controller -- linstor resource list-volumes
+-------------------------------------------------------------------------------------------------------------------------------------------+
| Node | Resource | StoragePool | VolNr | MinorNr | DeviceName | Allocated | InUse | State |
|===========================================================================================================================================|
| node1 | pvc-9599f79e-d825-4550-b044-5c577f1f0020 | pool1 | 0 | 1004 | /dev/drbd1004 | 32.91 MiB | Unused | UpToDate |
| node2 | pvc-9599f79e-d825-4550-b044-5c577f1f0020 | pool1 | 0 | 1004 | /dev/drbd1004 | 944 KiB | Unused | UpToDate |
| node3 | pvc-9599f79e-d825-4550-b044-5c577f1f0020 | DfltDisklessStorPool | 0 | 1004 | /dev/drbd1004 | | InUse | Diskless |
+-------------------------------------------------------------------------------------------------------------------------------------------+
现在已成功创建复制卷并验证数据是否可从多个节点访问。
重置启用节点,现在我们已经验证了复制工作,我们可以重置禁用的节点:
root@node1:~# kubectl uncordon node1
node/node1 uncordoned
我们现在已经成功设置了 Piraeus 数据存储,并使用它在 Kubernetes 集群中配置持久卷。
kubectl-linstor安装
kubectl-linstor是一个通过 kubectl 命令行执行 LINSTOR 命令的插件。要使用 kubectl linstor
需要使用Piraeus Operator。
wget https://github.com/piraeusdatastore/kubectl-linstor/releases/download/v0.2.1/kubectl-linstor-v0.2.1-linux-amd64.tar.gz
tar -zxvf kubectl-linstor-v0.2.1-linux-amd64.tar.gz kubectl-linstor
mv kubectl-linstor /usr/local/bin/
chmod +x /usr/local/bin/kubectl-linstor
查看节点
root@node1:~# kubectl linstor node list
╭────────────────────────────────────────────────────────╮
┊ Node ┊ NodeType ┊ Addresses ┊ State ┊
╞════════════════════════════════════════════════════════╡
┊ node1 ┊ SATELLITE ┊ 100.64.0.83:3366 (PLAIN) ┊ Online ┊
┊ node2 ┊ SATELLITE ┊ 100.64.1.175:3366 (PLAIN) ┊ Online ┊
┊ node3 ┊ SATELLITE ┊ 100.64.2.179:3366 (PLAIN) ┊ Online ┊
╰────────────────────────────────────────────────────────╯
查看存储池
root@node1:~# kubectl linstor storage-pool list
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
┊ StoragePool ┊ Node ┊ Driver ┊ PoolName ┊ FreeCapacity ┊ TotalCapacity ┊ CanSnapshots ┊ State ┊ SharedName ┊
╞════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
┊ DfltDisklessStorPool ┊ node1 ┊ DISKLESS ┊ ┊ ┊ ┊ False ┊ Ok ┊ ┊
┊ DfltDisklessStorPool ┊ node2 ┊ DISKLESS ┊ ┊ ┊ ┊ False ┊ Ok ┊ ┊
┊ DfltDisklessStorPool ┊ node3 ┊ DISKLESS ┊ ┊ ┊ ┊ False ┊ Ok ┊ ┊
┊ pool1 ┊ node1 ┊ FILE_THIN ┊ /var/lib/piraeus-datastore/pool1 ┊ 23.14 GiB ┊ 96.90 GiB ┊ True ┊ Ok ┊ ┊
┊ pool1 ┊ node2 ┊ FILE_THIN ┊ /var/lib/piraeus-datastore/pool1 ┊ 72.24 GiB ┊ 96.90 GiB ┊ True ┊ Ok ┊ ┊
┊ pool1 ┊ node3 ┊ FILE_THIN ┊ /var/lib/piraeus-datastore/pool1 ┊ 70.45 GiB ┊ 96.90 GiB ┊ True ┊ Ok ┊ ┊
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯