Piraeus 是面向 Kubernetes 的高性能、高可用性、简单、安全且与云无关的云原生存储解决方案,号称性能和稳定性都优于 Ceph/OpenEBS/Longhorn 等项目。Piraeus 对应的商业产品为LINSTOR 。
众所周知,本地存储具有高性能的优势,但它将应用程序绑定到特定节点,从而使应用程序难以调度,如果该节点或本地卷遇到故障并变得不可访问,则该容器也将变得不可访问。有了piraeus
的加持,使高性能的本地存储同时具备高可用的能力,在kubernetes集群中运行数据库、大数据等对性能要求高的有状态应用不再令人望而生畏。
Piraeus 项目成长路径:
官方网站:https://piraeus.io/
项目地址:https://github.com/piraeusdatastore/piraeus
Piraeus核心技术为基于操作系统内核的DRBD数据块复制技术来实现本地卷可高用。
Piraeus 项目能够具备高可用,高性能,丰富的企业级存储特性,有以下原因:
Ceph/OpenEBS/Longhorn
等项目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 |
博客链接: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 副本卷,这也取得了非常令人满意的结果。
项目地址: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
所有节点配置内核参数
echo fs.inotify.max_user_instances=8192 | tee -a /etc/sysctl.conf && sudo sysctl -p
下载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
创建storage cluster
$ kubectl apply -f - <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 - <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 | |
+------------------------------------------------------------------------------------------------------------------------------------------------+
支持的所有参数:https://linbit.com/drbd-user-guide/linstor-guide-1_0-en/#s-kubernetes-sc-parameters
我们现在已经成功部署和配置了 Piraeus 数据存储,并准备 PersistentVolume在 Kubernetes 中创建我们的第一个数据存储。
首先,我们将为我们的卷设置一个新的StorageClass。在StorageClass
中,我们指定上面的存储池:
$ kubectl apply -f - <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
参数说明:
查看创建的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 - <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 服务器创建一个部署,从我们的卷中提供文件。
$ kubectl apply -f - <apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app.kubernetes.io/name: web-server
template:
metadata:
labels:
app.kubernetes.io/name: web-server
spec:
containers:
- name: web-server
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: data-volume
EOF
短暂等待后,Pod 已完成Running
,我们的PersistentVolumeClaim
现在已完成Bound
:
$ kubectl wait pod --for=condition=Ready -l app.kubernetes.io/name=web-server
pod/web-server-84867b5449-hgdzx condition met
$ kubectl get persistentvolumeclaim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-volume Bound pvc-9e1149e7-33db-47a7-8fc6-172514422143 1Gi RWO piraeus-storage 1m
检查正在运行的容器,我们看到该卷已安装在我们预期的位置:
$ kubectl exec deploy/web-server -- df -h /usr/share/nginx/html
Filesystem Size Used Avail Use% Mounted on
/dev/drbd1000 973M 24K 906M 1% /usr/share/nginx/html
查看客户端linstor
,我们可以看到该卷已在 LINSTOR 中列出并由InUse
Pod 标记为。经过短暂的等待,可以看到 LINSTOR 将卷放在两个节点上,当一个节点故障后,pod会调度到第二个节点并挂载卷:
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-62bdaf29-188f-4e88-9c04-db7b7f6cca95 | DfltDisklessStorPool | 0 | 1000 | /dev/drbd1000 | | Unused | TieBreaker |
| node2 | pvc-62bdaf29-188f-4e88-9c04-db7b7f6cca95 | pool1 | 0 | 1000 | /dev/drbd1000 | 10.58 MiB | InUse | UpToDate |
| node3 | pvc-62bdaf29-188f-4e88-9c04-db7b7f6cca95 | pool1 | 0 | 1000 | /dev/drbd1000 | 2.39 MiB | Unused | UpToDate |
+---------------------------------------------------------------------------------------------------------------------------------------------+
我们现在已经成功设置了 Piraeus 数据存储,并使用它在 Kubernetes 集群中配置持久卷。
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 ┊ ┊
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯