Longhorn 是由 Rancher 实验室创建的一款云原生的、轻量级、可靠且易用的开源分布式块存储系统,后来由 CNCF 孵化。它借助 CSI 存储卷插件以外置的存储解决方案形式运行。Longhorn 遵循微服务的原则,利用容器将小型独立组件构建为分布式块存储,并使用编排工具来协调这些组件,从而形成弹性分布式系统。部署到 Kubernetes 集群上之后,Longhorn 会自动将集群中所有节点上可用的本地存储(默认为 /var/lib/longhorn/
目录所在的设备)聚集为存储集群,而后利用这些存储管理分布式、带有复制功能的块存储,且支持快照及数据备份操作。
面向现代云环境设计的存储系统的控制器随着待编排存储卷数量的急速增加也变得高度复杂。为了摆脱这种困境,Longhorn 充分利用了近年来关于如何编排大量容器的关键技术,采用微服务的设计模式,将大型复杂的存储控制器切分为每个存储卷一个专用的、小型存储控制器,而后借助现代编排工具来管理这些控制器,从而将每个 CSI 卷构建为一个独立的微服务。如图所示的存储架构中,3 个 Pod 分别使用了一个 Longhorn 存储卷,每个卷有一个专用的控制器(Engine
)资源和两个副本(Replica
) 资源,它们都是为了便于描述其应用而由 Longhorn 引入的自定义资源类型。
Engine 容器仅负责单个存储卷的管理,其生命周期与存储卷相同,因而它并非真正的 CSI 插件级别的卷控制器或节点插件。Longhorn 上负责处理来自 Kubernetes CSI 卷插件的 API 调用,以及完成存储卷管理的组件是 Longhorn Manager(node-driver-registrar),它是一个容器化应用且受 DaemonSet
控制器资源编排,在 Kubernetes 集群的每个节点上运行一个副本。Longhorn Manager 持续监视 Kubernetes API 上与 Longhorn 存储卷相关的资源变动,一旦发现新的资源创建,它负责在该卷附加的节点(即 Pod
被 Kubernetes 调度器绑定的目标节点)上创建一个 Engine
资源对象,并在副本相关的每个目标节点上相应创建一个 Replica
资源对象。
Kubernetes 集群内部通过 CSI 插件接口调用 Longhorn 插件以管理相关类型的存储卷,而 Longhorn 存储插件则基于 Longhorn API 与 Longhorn Manager 进行通信,卷管理之外的其他功能则要依赖 Longhorn Ul 完成,例如快照、备份、节点和磁盘的管理等。另外,Longhorn 的块设备存储卷的实现建立在 iSCSI 协议之上,因而需要调用 Longhorn 存储卷的 Pod 所在节点必须部署了相关的程序包,例如 open-iscsi
或 iscsiadm
等。
目前版本(v1.1.2)的 Longhorn 要求运行于 v1.13 或更高版本的 Docker 环境下,以及 v1.4 或更高版本的 Kubernetes 之上,并且要求各节点部署了 open-iscsi
、curl
、findmnt
、grep
、awk
、blkid
和 Isblk
等程序包。以 CentOS 7 安装基础环境为例:
yum -y install iscsi-initiator-utils curl util-linux
基础环境准备完成后,我们使用类似如下的命令即能完成 Longhorn 应用的部署:
$ kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
namespace/longhorn-system created
serviceaccount/longhorn-service-account created
clusterrole.rbac.authorization.k8s.io/longhorn-role created
clusterrolebinding.rbac.authorization.k8s.io/longhorn-bind created
customresourcedefinition.apiextensions.k8s.io/engines.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/replicas.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/settings.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/volumes.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/engineimages.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/nodes.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/instancemanagers.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/sharemanagers.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/backingimages.longhorn.io created
customresourcedefinition.apiextensions.k8s.io/backingimagemanagers.longhorn.io created
configmap/longhorn-default-setting created
podsecuritypolicy.policy/longhorn-psp created
role.rbac.authorization.k8s.io/longhorn-psp-role created
rolebinding.rbac.authorization.k8s.io/longhorn-psp-binding created
configmap/longhorn-storageclass created
daemonset.apps/longhorn-manager created
service/longhorn-backend created
deployment.apps/longhorn-ui created
service/longhorn-frontend created
deployment.apps/longhorn-driver-deployer created
$ kubectl get pod -n longhorn-system
NAME READY STATUS RESTARTS AGE
csi-attacher-54c7586574-4f5kk 1/1 Running 0 13m
csi-attacher-54c7586574-qkv97 1/1 Running 0 13m
csi-attacher-54c7586574-v2j8d 1/1 Running 0 13m
csi-provisioner-5ff5bd6b88-8qtbl 1/1 Running 0 13m
csi-provisioner-5ff5bd6b88-wzgpq 1/1 Running 0 13m
csi-provisioner-5ff5bd6b88-zjqjq 1/1 Running 0 13m
csi-resizer-7699cdfc4-cffvp 1/1 Running 0 13m
csi-resizer-7699cdfc4-d9cvk 1/1 Running 0 13m
csi-resizer-7699cdfc4-wmq8r 1/1 Running 0 13m
csi-snapshotter-8f58f46b4-j97p5 1/1 Running 0 13m
csi-snapshotter-8f58f46b4-q4mr7 1/1 Running 0 13m
csi-snapshotter-8f58f46b4-xwhcs 1/1 Running 0 13m
engine-image-ei-a5a44787-8mggj 1/1 Running 0 15m
engine-image-ei-a5a44787-bqv29 1/1 Running 0 15m
engine-image-ei-a5a44787-q2cst 1/1 Running 0 15m
instance-manager-e-3db801c5 1/1 Running 0 14m
instance-manager-e-6b2b140b 1/1 Running 0 15m
instance-manager-e-a7e8665f 1/1 Running 0 15m
instance-manager-r-9f307d66 1/1 Running 0 14m
instance-manager-r-cb3ab4ad 1/1 Running 0 15m
instance-manager-r-eb18aa64 1/1 Running 0 15m
longhorn-csi-plugin-85twv 2/2 Running 0 13m
longhorn-csi-plugin-lkdvl 2/2 Running 0 13m
longhorn-csi-plugin-rxlwj 2/2 Running 0 13m
longhorn-driver-deployer-5479f45d86-r6hcb 1/1 Running 0 16m
longhorn-manager-88n87 1/1 Running 1 16m
longhorn-manager-j4cbz 1/1 Running 0 16m
longhorn-manager-qb4hh 1/1 Running 0 16m
longhorn-ui-79f8976fbf-2x79z 1/1 Running 0 16m
可以看到,该部署清单会在默认的 longhorn-system
名称空间下部署 csi-attacher
、csi-provisioner
、csi-resizer
、engine-image-ei
、longhorn-csi-plugin
和 longhorn-manager
等应用相关的 Pod
对象,待这些 Pod
对象成功转为 Running
状态之后即可测试使用 Longhorn CSI 插件。
该部署清单还会默认创建如下面资源清单中定义的名为 longhorn
的 StorageClass
资源:
kind: StorageClass # 资源类型
apiVersion: storage.k8s.io/v1 # API 群组及版本
metadata:
name: longhorn
provisioner: driver.longhorn.io # 存储供给驱动
allowVolumeExpansion: true # 是否支持存储卷弹性伸缩
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3" # 副本数量
staleReplicaTimeout: "2880" # 过期副本超时时长
fromBackup: ""
它以部署好的 Longhorn 为后端存储系统,支持存储卷动态预配机制。我们也能够以类似的方式定义基于该存储系统的、使用了不同配置的其他 StorageClass
资源,例如仅有一个副本以用于测试场景或对数据可靠性要求并非特别高的应用等。
随后,我们随时可以按需创建基于该存储类的 PVC 资源来使用 Longhorn 存储系统上的持久存储卷提供的存储空间。下面的示例资源清单(pvc-dyn-longhorn-demo.yaml
)便定义了一个基于 Longhorn 存储类的 PVC
,它请求使用 2GB
的空间。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-dyn-longhorn-demo
namespace: default
spec:
accessModes: ["ReadWriteMany"]
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
storageClassName: longhorn
如前所述,Longhorn 存储设备支持动态预配,于是默认以存储类 longhorn
为模板 PVC
在无满足其请求条件的 PV
时,可由控制器自动创建出适配的 PV
卷来。下面两条命令及结果也反映了这种预配机制。
$ kubectl apply -f pvc-dyn-longhorn-demo.yaml
persistentvolumeclaim/pvc-dyn-longhorn-demo created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-dyn-longhorn-demo Bound pvc-61085d88-be9e-45d1-8475-2511ae300810 2Gi RWX longhorn 14m
对于每个存储卷,Longhorn 存储系统都会使用自定义的 Volumes
类型资源对象维持及跟踪其运行状态,每个 Volumes
资源都会有一个 Engines
资源对象作为其存储控制器,如下面的两个命令及结果所示:
$ kubectl get volume -n longhorn-system
NAME STATE ROBUSTNESS SCHEDULED SIZE NODE AGE
pvc-61085d88-be9e-45d1-8475-2511ae300810 detached unknown True 2147483648 115m
$ kubectl get engine -n longhorn-system
NAME STATE NODE INSTANCEMANAGER IMAGE AGE
pvc-61085d88-be9e-45d1-8475-2511ae300810-e-1ad1ec24 stopped 115m
Engines
资源对象的详细描述或资源规范中的 spec
和 status
字段记录有当前资源的详细信息,包括关联的副本、purge
状态、 恢复状态和快照信息等。
$ kubectl describe engine pvc-61085d88-be9e-45d1-8475-2511ae300810-e-1ad1ec24 -n longhorn-system
Name: pvc-61085d88-be9e-45d1-8475-2511ae300810-e-1ad1ec24
Namespace: longhorn-system
Labels: longhornnode=
longhornvolume=pvc-61085d88-be9e-45d1-8475-2511ae300810
Annotations: <none>
API Version: longhorn.io/v1beta1
Kind: Engine
Metadata:
Creation Timestamp: 2021-07-16T09:57:02Z
Finalizers:
longhorn.io
Generation: 3
Owner References:
API Version: longhorn.io/v1beta1
Kind: Volume
Name: pvc-61085d88-be9e-45d1-8475-2511ae300810
UID: 23694c8c-33cd-41c4-a280-a2084eb6e8b6
Resource Version: 16039903
Self Link: /apis/longhorn.io/v1beta1/namespaces/longhorn-system/engines/pvc-61085d88-be9e-45d1-8475-2511ae300810-e-1ad1ec24
UID: 3875014c-e5bf-4fd8-92e0-a2cafedace02
Spec:
Backup Volume:
Desire State: stopped
Disable Frontend: false
Engine Image: longhornio/longhorn-engine:v1.1.2
Frontend: blockdev
Log Requested: false
Node ID: # 绑定的节点,它必须与调用了该存储卷的 Pod 运行于同一节点
Replica Address Map: # 关联的存储卷副本
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-9d236e63: 10.244.2.14:10000
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-9f156bdf: 10.244.0.14:10000
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-c0517a14: 10.244.1.48:10000
Requested Backup Restore:
Revision Counter Disabled: false
Salvage Requested: false
Upgraded Replica Address Map:
Volume Name: pvc-61085d88-be9e-45d1-8475-2511ae300810
Volume Size: 2147483648
Status:
Backup Status: <nil>
Current Image:
Current Replica Address Map:
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-9d236e63: 10.244.2.14:10000
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-9f156bdf: 10.244.0.14:10000
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-c0517a14: 10.244.1.48:10000
Current Size: 2147483648
Current State: stopped
Endpoint:
Instance Manager Name:
Ip:
Is Expanding: false
Last Expansion Error:
Last Expansion Failed At:
Last Restored Backup:
Log Fetched: false
Owner ID: k8s-master1
Port: 0
Purge Status: <nil>
Rebuild Status: <nil>
Replica Mode Map: <nil>
Restore Status: <nil>
Salvage Executed: false
Snapshots:
Volume - Head:
Children:
Created: 2021-07-16T09:57:29Z
Labels:
Name: volume-head
Parent:
Removed: false
Size: 101867520
Usercreated: false
Snapshots Error:
Started: false
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Stop 8s (x2 over 8s) longhorn-engine-controller Stops pvc-61085d88-be9e-45d1-8475-2511ae300810-e-1ad1ec24
Replicas
也是 Longhorn
提供的一个独立资源类型,每个资源对象对应着一个存储卷副本,如下面的命令结果所示:
$ kubectl get replica -n longhorn-system
NAME STATE NODE DISK INSTANCEMANAGER IMAGE AGE
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-9d236e63 running k8s-master1 16bd736f-bf18-4209-bc76-2d689cabfcfb instance-manager-r-cb3ab4ad longhornio/longhorn-engine:v1.1.2 57m
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-9f156bdf running k8s-master2 95e94f5e-484e-4ca6-b362-a0cf6ffc0c9b instance-manager-r-9f307d66 longhornio/longhorn-engine:v1.1.2 57m
pvc-61085d88-be9e-45d1-8475-2511ae300810-r-c0517a14 running k8s-node1 9106daad-689d-4d39-8a39-68573d3d6dae instance-manager-r-eb18aa64 longhornio/longhorn-engine:v1.1.2 57m
基于 Longhorn 存储卷的 PVC 被 Pod
引用后,Pod
所在的节点便是该存储卷 Engine
对象运行所在的节点,Engine
的状态也才会由
Stopped
转为 Running
。示例清单 test-longhorn-deploy.yaml
定义了一个调用 pvc/pvc-dyn-longhorn-demo
资源的 Deployment
资源,因而该 Deployment
控制器管理的 Pod
所在的节点便是该 PVC
后端 PV
相关的 Engine
绑定的节点,如下面 3 个命令及其结果所示。
$ cat test-longhorn-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-longhorn
namespace: default
labels:
app: test-longhorn
spec:
selector:
matchLabels:
app: test-longhorn
replicas: 1
template:
metadata:
labels:
app: test-longhorn
spec:
containers:
- name: test-longhorn
image: zze326/test-tools
volumeMounts:
- name: longhorn-pvc
mountPath: /data
volumes:
- name: longhorn-pvc
persistentVolumeClaim:
claimName: pvc-dyn-longhorn-demo
restartPolicy: Always
$ kubectl apply -f test-longhorn-deploy.yaml
deployment.apps/test-longhorn created
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE
test-longhorn-b6b8b8667-9btgg 1/1 Running 0 74s
$ kubectl get pod test-longhorn-b6b8b8667-9btgg -o jsonpath="{.spec.nodeName}"
k8s-master2
$ kubectl get engine pvc-61085d88-be9e-45d1-8475-2511ae300810-e-1ad1ec24 -n longhorn-system -o jsonpath="{.spec.nodeID}"
k8s-master2
由以上 Longhorn 存储系统的部署及测试结果可知,该存储系统不依赖于任何外部存储设备,仅基于 Kubernetes 集群工作节点本地的存储即能正常提供存储卷服务,且支持动态预配等功能。但应用于生产环境时,还是有许多步骤需要优化,例如将数据存储与操作系统等分离到不同的磁盘设备、是否可以考虑关闭底层的 RAID 设备等,具体请参考 Longhorn 文档中的最佳实践。
Longhorn 还提供了一个 Web 服务来便于我们通过 Kubernetes 集群外部的浏览器访问该用户接口以管理 Longhorn 各项功能,我们需要把相关的 Service
对象的类型修改为 NodePort
:
$ kubectl patch svc/longhorn-frontend -p '{"spec":{"type":"NodePort"}}' -n longhorn-system
service/longhorn-frontend patched
$ kubectl get svc -n longhorn-system -lapp=longhorn-ui
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
longhorn-frontend NodePort 10.0.0.241 <none> 80:31851/TCP 100m
随后,我们经由任意一个节点的 IP 地址节点端口(例如上面命令中自动分配而来的 31851
)即可访问该 UI, 如下图所示:
节点、存储卷、备份和系统设置导航标签各自给出了相关功能的配置入口,更多其它功能就等着你去探索啦~~附上 Longhorn 官方文档:
需要注意的是,考虑到该 UI 并没有内嵌用户认证机制,如此将其发布到集群外部可能会带来安全风险。
评论区