ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

单节点K8s集群部署Longhorn:持久化存储与快照备份实战

单节点K8s集群部署Longhorn:持久化存储与快照备份实战 在单节点 K8s 集群上部署 Longhorn第一眼看过去确实有点“杀鸡用牛刀”的意思。毕竟 Longhorn 最常被提到的关键词是分布式块存储、多副本、跨节点容灾而单节点集群本身就没有第二个节点可容灾多副本在物理层面也谈不上高可用。但我实际完整跑了一遍之后发现这个组合并没有想象中那么折腾反而把“应用数据存在哪、怎么恢复、怎么扩容”这些 K8s 持久化里最烦的问题变成了有 UI、有 API、有快照的一套标准流程。这篇文章就是记录我这次部署的真实过程包括环境准备、Helm 安装、针对单节点的参数调整、卷挂载验证和踩坑排查给同样在单节点 K8s 环境里跑有状态应用的朋友做参考。1. 单节点 K8s 上为什么还要装 Longhorn1.1 Longhorn 到底解决了什么问题Longhorn 是 Rancher 主导的云原生分布式块存储项目说白了就是一套跑在 Kubernetes 里的存储控制器和 CSI 驱动。它把节点上的普通磁盘空间再次抽象成卷然后以 Kubernetes 原生 API 的方式提供 PersistentVolume、PersistentVolumeClaim、StorageClass。日常使用中你不需要关心底层是 LVM、分区还是目录只要创建 PVC 就能给 Pod 挂上一块持久化盘。K8s 自带的能力里并不是没有持久化emptyDir是临时目录Pod 删除就没了hostPath直接把宿主机的目录映射给 Pod数据确实是持久的但根本没有卷管理的概念。我做了个 PVC删掉之后数据会不会清掉卷空间满了能不能扩应用数据改了能不能回滚到某个时间点这些需求在hostPath上都得靠运维手工解决。Longhorn 把这些能力补上了卷生命周期托管、在线扩容、快照、回滚、备份到外部存储。有人可能会说单节点上要这些高级功能有什么用这里有个常见误区Longhorn 的核心价值并不只有“多副本容灾”还有一套完整的数据生命周期管理。你在单节点上跑 GitLab、Jenkins、MySQL 这类有状态服务时数据出问题的概率并不低。写一半断电、卷被打满、误删文件、升级踩坑需要回退这些场景下快照和备份比“再找个节点放副本”更实际。1.2 单节点用 Longhorn 的真实场景我最早觉得单节点 K8s 配 Longhorn 是叠加复杂度后来想明白其实有三个很典型的场景完全值得这么干。第一个是家用服务器或实验室环境。一台主机装个 K3s上面跑 Nextcloud、Home Assistant、Prometheus、数据库这些服务。以前每个应用的数据目录散落在各个 hostPath 里备份脚本要一个个配置路径麻烦且有漏配风险。用了 Longhorn 之后所有卷都能集中展示备份目标统一挂到 NFS 或对象存储管理半径一下子缩小了。第二个是开发测试环境。很多测试场景需要验证真实 CSI 行为和存储能力纯hostPath摸不到这些东西。单节点上部署 Longhorn至少能测清楚 PVC 创建、快照、在线扩容、回收策略这些行为等以后真的上了多节点集群改动会很小。第三个是边缘或离线场景。单台轻量服务器上部署一套 K8s 跑业务边缘节点没有第二台机器做数据同步但业务数据又不能丢。Longhorn 的卷文件全部存在节点本地同时支持 NAS 或者 S3 备份断电、换盘之后也能恢复这套机制在边缘场景一样有价值。1.3 为什么不直接在单节点上用 local-path-provisioner提到单节点持久化很多人第一反应是 Rancher 自带的 local-path-provisioner它确实轻量K3s 默认就带。但在准备阶段我对比了一下最后还是选了 Longhorn原因其实很简单local-path 只解决了“PVC 能不能用”的问题没有解决“卷数据怎么管理”的问题。我列了一张对比表直观一点能力项local-path-provisionerLonghorn实现原理把 PVC 映射到节点上的一个目录卷以块设备模型写入独立目录并由 engine 管理生命周期管理基本没有删除 PVC 后文件可能残留按 ReclaimPolicy 自动清理卷数据快照不支持原生支持可基于时间点创建和回滚在线扩容一般不支持需要手动处理支持CSI resizer 自动扩展文件系统外部备份不支持支持 NFS、S3 等备份目标管理界面无有完整 Web UI能看到节点、卷、副本状态多副本无概念支持但单节点上建议设为 1看到这里你应该明白选 Longhorn 不是为了多副本。单节点上就算你设置 3 个副本它们仍然全部落在这同一个节点的同一块磁盘上盘一坏、数据一起没高可用是空谈反而白白放大写放大。真正让 Longhorn 值得装的是它那套卷管理 API、快照机制和备份能力。因此我后面的所有配置都是围绕“单节点 单副本 备份兜底”这个思路展开的。2. 部署前必须做好的环境准备2.1 单节点 K8s 集群的软硬件要求先说你自己的 K8s 集群基础我用的是 K3s 单节点安装Kubernetes 版本在 v1.28 左右这完全在 Longhorn 的支持范围内。其实 Longhorn 对上游 K8s 和 K3s 都支持得很好版本不要太老v1.26 以上基本通畅。硬件要求不算苛刻一般来说CPU 至少 2 核内存至少 4GB这是底线。Longhorn 安装之后会起一堆控制器和 CSI 组件虽然单个组件占用不高但叠加起来还是很可观。我实际观察过一个空的 Longhorn 安装长期占用内存在 1GB 左右这还不算卷运行时的 engine 和 replica 进程。节点内存如果小于 4GB部署后 Pod 频繁被杀不是没可能。磁盘方面Longhorn 默认把卷数据放在/var/lib/longhorn/。单节点环境我强烈建议给这个目录规划独立数据盘不要和系统盘混在一起否则你跑两个有状态应用的卷系统盘就被日志、镜像、临时文件慢慢塞满。可以先用df -h检查一下分区情况如果/var/lib/longhorn所在分区剩余空间不足就趁部署前把数据盘挂到指定的目录后面通过参数指定。2.2 安装 iSCSI 客户端和 NFS 相关依赖这是整个部署过程中最容易踩坑的一个环节。Longhorn 的卷最终以 iSCSI 块设备的方式呈现给 Kubelet需要在每个节点上安装 iSCSI 发起端工具。Debian / Ubuntu 系执行sudo apt-get update sudo apt-get install -y open-iscsi nfs-common curl sudo systemctl enable --now iscsidCentOS / RHEL 系执行sudo yum install -y iscsi-initiator-utils nfs-utils curl sudo systemctl enable --now iscsid装完之后检查一下 iSCSI 服务状态Debian 系里最典型的问题是open-iscsi装了但iscsid没起来后面卷挂载的时候会一直报连接失败。命令是systemctl status iscsid另外某些精简内核上iscsi_tcp模块可能没加载Longhorn 的 instance-manager 跑起来之后连不上 target也会导致挂载失败。保险起见手动加载一下内核模块sudo modprobe iscsi_tcp sudo modprobe configfs echo iscsi_tcp | sudo tee /etc/modules-load.d/longhorn.conf echo configfs | sudo tee -a /etc/modules-load.d/longhorn.confNFS 客户端不是必须的但只要你后面想用 NAS 做备份目标或者想用 Longhorn 的 ReadWriteMany 能力就一定提前装好。我建议单节点直接装上免得以后要用的时候再补依赖。2.3 单节点控制面污点如何处理如果你是用 kubeadm 搭的单节点控制面master 节点默认带有node-role.kubernetes.io/control-plane:NoSchedule污点。Longhorn 的很多控制器 Pod 在安装后会调度不到这个节点上表现就是Pod Pending。这里有两个思路。第一给 Longhorn 配置污点容忍这是最干净的办法不会改变节点原有调度语义。在 Helm 安装时通过参数写入--set defaultSettings.taintTolerationnode-role.kubernetes.io/control-plane:NoSchedule如果节点上除了控制面污点还有其他污点可以用逗号分隔比如key1value1:NoSchedule,key2:NoExecute。配置之后Longhorn 的核心组件会容忍这些污点并调度到唯一节点上。第二如果你觉得单节点集群无所谓直接把污点清理掉也可以kubectl taint nodes --all node-role.kubernetes.io/control-plane-不过我个人不推荐这个做法。不少人跑了一段时间之后会往集群里加真正的 worker 节点到时候反而希望 master 保持不调度业务容器。所以尽量用容忍方案而不是把调度规则一刀切掉。2.4 确定 Longhorn 数据目录和备份策略Longhorn 有一个全局默认数据路径默认是/var/lib/longhorn。如果数据盘挂载点是/data/longhorn-data可以在安装时指定--set defaultSettings.defaultDataPath/data/longhorn-data需要注意这个目录在安装前就要建好并且有合适的写权限否则节点会进入不可用状态。我实际测试时用的是默认路径因为测试机的 SSD 都在系统盘上。但正式使用请务必把数据路径和系统盘拆开磁盘满的后果不只是存储卷不可用还可能连带系统和 K8s 组件崩溃。还有一点值得提前想好单节点没有第二块盘做本地容灾那备份目标最好在部署时就规划好。Longhorn 支持 NFS、S3、Azure Blob 等备份目标配置入口在 Web UI 的Settings - Backup Target。我现在用的就是局域网 NAS 上的 NFS 目录后期会专门写备份和恢复的测试流程。3. 用 Helm 快速部署 Longhorn 的完整过程3.1 添加 Helm 仓库并执行安装部署 Longhorn 我推荐使用 Helm升级、回滚、传参都比较清晰。整个安装命令并不复杂helm repo add longhorn https://charts.longhorn.io helm repo update kubectl create namespace longhorn-system helm install longhorn longhorn/longhorn \ --namespace longhorn-system \ --create-namespace \ --set defaultSettings.defaultReplicaCount1这里最关键的参数就是defaultSettings.defaultReplicaCount1。Longhorn 默认的副本数是 3这个默认值在多节点集群里是合理的但在单节点上意义不大而且会带来两种糟糕情况一是卷状态一直显示 Degraded因为部分副本调度不成功二是在某些配置下把多个副本硬塞到同一个节点电量和 IO 都被白白浪费。所以我从安装开始就明确指定副本数。如果你不想用 HelmLonghorn 也提供了一体化 YAMLkubectl create namespace longhorn-system kubectl -n longhorn-system apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.0/deploy/longhorn.yaml我最后还是选择了 Helm主要原因是后续调参不需要改整份 YAML一条helm upgrade就搞定。3.2 安装后必看的组件状态安装命令执行完不要急着去创建卷先观察 Pod 是否全部进入 Running 状态kubectl -n longhorn-system get pods -o wide正常情况下你会看到以下几类组件longhorn-ui-*Web 界面一个 Deploymentlonghorn-manager-*Longhorn 的核心控制器负责卷、节点、引擎的管理longhorn-driver-deployer-*负责部署 CSI driver 相关组件csi-attacher-*、csi-provisioner-*、csi-resizer-*、csi-snapshotter-*K8s 标准的 CSI sidecarinstance-manager-*和engine-image-*在真正创建卷之后才出现单节点集群里longhorn-manager只会有一个副本很容易出现它所在的 Pod 还没 Ready其他组件在等待的情况。所以第一次安装后多等一两分钟是很正常的。用以下命令确认所有 Deployment 的 rollout 状态kubectl -n longhorn-system rollout status deploy/longhorn-ui kubectl -n longhorn-system rollout status deploy/longhorn-driver-deployer如果有组件一直CrashLoopBackOff或者Pending先看事件不要盲目重装。最常见的就是前面说的节点污点没处理Pod 根本调度不上去。用kubectl describe pod看日志和事件比翻安装文档更快定位。3.3 访问 Longhorn UI 并确认默认存储类Longhorn 装完之后会创建一个名为longhorn的 StorageClass并将它设置为默认存储类。在 K3s 环境里默认存储类是local-path所以两者会发生冲突。用下面的命令看一下kubectl get storageclass如果longhorn的storageclass.kubernetes.io/is-default-class不是 true或者local-path仍然是默认需要手动调整。我先让 local-path 退出默认kubectl patch storageclass local-path \ -p {metadata:{annotations:{storageclass.kubernetes.io/is-default-class:false}}}再把 longhorn 设为默认kubectl patch storageclass longhorn \ -p {metadata:{annotations:{storageclass.kubernetes.io/is-default-class:true}}}这一步非常重要。因为很多应用创建 PVC 时根本不写storageClassName如果集群默认存储类还是local-path那么你以为的 Longhorn 卷其实全跑到了 local-path 上后面在 Longhorn UI 里看到卷为空会以为安装出了问题实际是调度到了另一个存储类。访问 Longhorn UI 很简单用 port-forwardkubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80浏览器打开http://localhost:8080就能看到 Dashboard。Dashboard 展示当前集群节点情况、卷数量、副本状态。第一次进去应该能看到你的节点是 healthy 的但还没有任何卷。4. 针对单节点集群的关键配置与参数调优4.1 副本数必须改成 1以及如何修正已有卷安装时已经把全局默认副本数设成 1 了但还有个坑Longhorn 的 StorageClass 参数里也能覆盖副本数。如果你创建 StorageClass 的时候写了numberOfReplicas: 2最终卷还是按 2 个副本建。单节点上这个值一定要明确写 1。如果是安装前没设置卷已经创建了怎么办可以通过 CRD 直接修改卷规格kubectl -n longhorn-system get volumes.longhorn.io输出里能看到每个 Longhorn 卷对应底层 PVC 的名称找到你要改的卷执行kubectl -n longhorn-system edit volume pvc-xxxx把spec.numberOfReplicas改成 1保存之后 Longhorn 会自动把多余的副本清理掉。更省事的方式是在 UI 中点Volume - Edit把 Replicas 改成 1效果一样。这里我想多说一句单节点上用多副本不但没有物理容灾效果还会拖慢性能。每个副本都是一个完整的块设备写入要多占一倍磁盘 IO但数据都写在同一块盘上没有可靠性收益。如果真的要防数据丢失重点应该放在定期快照和备份到外部 NAS 上。4.2 自建 StorageClass 参数选择Longhorn 默认 StorageClass 已经能直接用但如果你想针对不同负载可以自己创建一个更明确的 StorageClass。我在单节点上使用的模板如下apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: longhorn-single annotations: storageclass.kubernetes.io/is-default-class: true provisioner: driver.longhorn.io allowVolumeExpansion: true reclaimPolicy: Delete volumeBindingMode: Immediate parameters: numberOfReplicas: 1 staleReplicaTimeout: 30 dataLocality: disabled fsType: ext4几个关键点说明一下allowVolumeExpansion: true必须保留否则 PVC 在线扩容不会生效。dataLocality: disabled是默认行为数据可能不在调度 Pod 的节点本地。但在单节点上反正就一个节点disabled 和 best-effort 的结果差不多。fsType: ext4是默认文件系统数据库类应用如果对 fsync 性能敏感可以改成 xfs 并配合格式化参数但日常使用 ext4 完全够。reclaimPolicy: Delete表示删除 PVC 时底层卷数据也会删除。如果不想删除 PVC 把数据一起带上可以改成 Retain但那样就需要手动清理数据日常测试阶段还是 Delete 顺手。关于 ReadWriteManyLonghorn 支持 RWX但它内部是用 NFS Server Pod 实现的。单节点上 RWX 是可以用的但每个 RWX 卷要额外起一个 NFS 组件IO 路径多一层性能会有损耗。单节点场景能用 RWO 解决的问题尽量不要引入 RWX。4.3 快照、备份目标和监控安装完成后建议去 UI 的Settings - General里看看几个默认参数。单节点上我把快照频率设置为每小时保留 3 份。这个参数在 UI 里叫Snapshot Count它控制的是卷自动快照数量上限不是周期。真正定时快照要靠 Kubernetes CronJob 调 Longhorn API或者用 UI 手动点。不要以为设置了数量限制就等于自动备份。备份目标建议用 NFS配置路径在Settings - Backup Target填入类似nfs://192.168.1.100:/volume/longhorn-backup的地址。填写完之后在卷页面选择某个快照点创建 Backup数据就会推到 NAS。第一次推全量之后是增量备份速度还是比较可观的。监控方面Longhorn 的 Dashboard 自带一些节点、卷层面的数据能看 IOPS、吞吐、延迟这些指标。如果你有一套 Prometheus也可以让监控抓取 Longhorn 的 metrics 端点但那是另一个话题。至少先用 UI 里的状态面板做到心中有数卷健康度、副本位置、剩余空间都能看到。5. 创建 PVC、部署应用并验证持久性5.1 创建测试 PVC 并部署应用装完不验证等于白装。我的习惯是用一个最小化的 PVC Deployment 组合来验证整条链路。先创建 PVCapiVersion: v1 kind: PersistentVolumeClaim metadata: name: k8s-longhorn-test spec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 2Gi接着创建一个写入测试文件的 DeploymentapiVersion: apps/v1 kind: Deployment metadata: name: longhorn-test spec: replicas: 1 selector: matchLabels: app: longhorn-test template: metadata: labels: app: longhorn-test spec: containers: - name: busybox image: busybox:latest command: [/bin/sh, -c, echo hello-longhorn /data/test.txt sleep 3600] volumeMounts: - name: data mountPath: /data volumes: - name: data persistentVolumeClaim: claimName: k8s-longhorn-test创建完先确认 PVC 绑定kubectl get pvc k8s-longhorn-test状态应该是 Bound。这时候再去 Longhorn UI 看 Volume 列表能看到一个名为pvc-k8s-longhorn-test的卷健康状态是 healthy。5.2 验证数据持久性与 Pod 重建PVC 绑定只是第一步关键要看数据能不能活过 Pod 重建。先确认 Pod 写入了文件kubectl exec -it deploy/longhorn-test -- cat /data/test.txt然后强制删除 Podkubectl delete pod -l applonghorn-testDeployment 会自动重新拉起一个 Pod再次执行kubectl exec -it deploy/longhorn-test -- cat /data/test.txt这时数据还在说明卷确实完成了“Pod 删除、卷保留”的模型。再进一步把整个 Deployment 删掉再重新 apply 同一个 YAML。只要 PVC 没有删重新创建的 Pod 挂载的是同一个 PV数据依旧在kubectl delete deployment longhorn-test kubectl apply -f longhorn-test.yaml这一步看起来简单但它验证的是 K8s 的 PV/PVC 引用关系和 Longhorn 的卷生命周期管理是否正常。如果数据丢了大概率是你配置的reclaimPolicy有问题或者 PVC 被意外删除了。5.3 在线扩容与快照回滚演练验证完持久性我建议顺手把扩容和快照都演练一遍这两项才是 Longhorn 相比 hostPath 的核心体验。在线扩容前先确认 StorageClass 里启用了allowVolumeExpansion然后修改 PVC 请求容量kubectl patch pvc k8s-longhorn-test \ --typejson \ -p[{op: replace, path: /spec/resources/requests/storage, value: 3Gi}]等一会儿PVC 的容量应该变成 3Gi文件系统大小也会自动扩展。Longhorn 的 CSI resizer 会调用文件系统扩容不需要你手动进去 resize。如果卡住看csi-resizer日志或者确认 PVC 正在被 Pod 使用。K8s 的 PVC 扩容只支持增大不支持缩小这个要记住。快照回滚是另一个高价值操作。流程是这样的先在 UI 的 Volume 页面创建第一个快照比如叫snap-before-test。然后在 Pod 里删除原文件并写一个新的文件kubectl exec -it deploy/longhorn-test -- sh -c rm /data/test.txt echo after-snapshot /data/new.txt接着把 Deployment 副本数缩到 0让卷不再被 Pod 挂载kubectl scale deploy longhorn-test --replicas0在 UI 中等待卷变为 Detached 状态然后选中之前创建的快照点击 Revert。回滚完成后再把副本数调回 1kubectl scale deploy longhorn-test --replicas1这时候再进 Pod 查看test.txt应该回来了new.txt被清掉。这里有一个细节快照回滚时卷必须处于 Detached 状态否则可能失败或者产生异常。所以操作前先缩容应用回滚完成再恢复不要嫌麻烦。6. 部署后常踩的坑与排查思路6.1 Open-iSCSI 缺失导致的卷挂载失败这是单节点部署 Longhorn 最常见的翻车点。现象是 PVC 一直 Pending或者 Pod 处于 ContainerCreating事件里出现类似MountVolume.MountDevice failed for volume pvc-xxx : rpc error: rpc exiting排查步骤不复杂journalctl -u kubelet --since -10m | grep -i iscsi dmesg | tail -50如果看到 iSCSI 连接失败的日志首先确认节点上open-iscsi是否安装、iscsid服务是否启动。我遇到过 Debian 上装完依赖之后iscsid没有自动 start手动执行一次sudo systemctl start iscsid就能解决。另外确认iscsi_tcp内核模块是否加载缺少模块通常报错更底层直接在 dmesg 里能看到。6.2 Longhorn 组件 CrashLoopBackOff安装之后如果发现longhorn-driver-deployer或csi-plugin这些组件一直在 CrashLoopBackOff不要先怀疑 Longhorn 本身。第一件事看事件kubectl -n longhorn-system get events --sort-by.lastTimestamp我遇到的情况几乎都是特权问题。Longhorn 的 CSI 组件需要特权模式访问宿主机设备在 K3s 里如果安装时启用了类似于限制特权容器的策略组件就会启动失败。另一个原因是组件调度不到带有污点的主节点也就是前面第二章节说的因此安装前就要设置好污点容忍。还有一类比较隐蔽的问题节点磁盘空间过满longhorn-manager写元数据失败也会表现为 CrashLoopBackOff。这时候df -h是最快的检测命令别上来就重装。6.3 卷状态 Degraded但不报错如果你装完 Longhorn 之后在 UI 看到某个卷是 Degraded但 K8s 侧 PVC 是 BoundPod 也正常运行十有八九是副本数配置不对。单节点上用默认副本数 2 或 3卷的期望副本数永远无法完全满足健康状态就会是 Degraded。处理方式前面已经写过把卷的numberOfReplicas改成 1。改完之后引擎会重建状态从 Degraded 慢慢变成 Healthy。千万不要在 Degraded 状态下反复删卷重建那样只会让自己越来越乱。小提示这个状态在安装后最开始可能不出现因为 Longhorn 默认副本数 3 且单节点上调度会很吃力等第一个测试 PVC 创建后才会暴露。所以安装时设置defaultReplicaCount1真的不能省这个参数就是为单节点准备的。6.4 节点重启后的恢复流程单节点集群里节点重启等于整个集群重启。Longhorn 的组件会随着 K8s 拉起重新启动Pod 挂载卷通常需要一点时间。我实际重启过一次过程是等节点 Kubelet 恢复然后观察 longhorn-system 的所有 Pod 状态。kubectl -n longhorn-system get pods -o wide正常情况下几分钟内组件会全部 Running。如果某个有状态应用的 Pod 卡在 ContainerCreating优先看 kubelet 日志journalctl -u kubelet --since -5m | grep -i mount\|iscsi如果是 iSCSI 连接恢复慢等一会儿通常会自己恢复。切忌发现挂不上就立刻删 PVC 或者删 Longhorn 卷那会把数据和元数据一起弄丢。等待时间超过 10 分钟还未恢复再去翻 instance-manager 的日志kubectl -n longhorn-system logs instance-manager-pod-name从实践上讲单节点 Longhorn 的恢复流程本身并不复杂大多数问题都出在依赖缺失和参数配置上。你要做的就是先把前面的 open-iscsi、污点容忍、副本数这三个问题解决掉后续会顺畅很多。以上就是我这次在单节点 K8s 集群上完整部署 Longhorn 的过程与总结。如果你也在家用服务器或测试环境里需要给有状态应用一个可靠的持久化方案Longhorn 值得直接纳入你的工具箱。先从最小 PVC 开始跑把快照和备份补上再考虑更高级的 RWX 和监控这套组合能陪你走很远。
返回列表