CNCF沙箱的容器原生存储项目,提供本地卷与复制卷两类引擎
OpenEBS 是 CNCF 沙箱项目,定位是「为 Kubernetes 而生的容器原生存储」。它与 Longhorn、Rook 的最大区别在于它不是一套存储,而是一组可选引擎的集合:每个引擎对应一类存储需求,可以按工作负载分别选用,互不干扰。
当前版本线为 v4.x(v4.6.x 系列),架构上把能力收敛为两个核心服务:
Local 本地卷。数据只存在于单个节点,不做副本。容量大、延迟低、无冗余。
包含 Hostpath、LVM、ZFS、Rawfile 四种实现。
Replicated 复制卷。以 Mayastor 为唯一实现,基于 NVMe-oF TCP 跨节点复制,有副本冗余。
这条边界要记牢:只有 Mayastor 提供冗余,其余引擎都是本地卷,节点故障即数据不可用。很多人以为「装了 OpenEBS 就有高可用」,这是最常见的误解。
历史包袱提醒:早期广泛使用的 cStor 与 Jiva 两个引擎已于 2024 年 4 月被废弃,相关仓库迁入 CNCF 名下的 openebs-archive 组织并逐步归档。它们仍能从归档仓库安装到老集群上,但不在新 Helm chart 中提供,也不推荐用于任何新部署。看到基于 cStor 的教程时,应当直接跳过。
引擎 类型 冗余 调度约束 典型场景
Local PV Hostpath 本地卷 无 节点亲和 开发测试、单节点、缓存
Local PV LVM 本地卷 无 节点亲和 需要快照/克隆的本地块设备
Local PV ZFS 本地卷 无 节点亲和 需要压缩、去重、校验和的场景
Local PV Rawfile 本地卷 无 节点亲和 基于文件的卷,支持 CoW 快照/克隆
Mayastor 复制卷 有 跨节点复制 需要高可用的数据库、有状态服务
# 所有引擎通用
Kubernetes 1.23 及以上、Linux 内核 5.15 及以上、Helm 3.2 及以上
# Local PV Hostpath:仅需一个可写的目录(默认 /var/openebs/local)
# Local PV LVM:节点需装 LVM2,并加载 dm-snapshot 模块,预先建好卷组
sudo apt-get install -y lvm2 && sudo modprobe dm-snapshot
sudo pvcreate /dev/sdb && sudo vgcreate lvmvg /dev/sdb
# Local PV ZFS:节点需装 ZFS 工具并预先建好池
sudo apt-get install -y zfsutils-linux
sudo zpool create zfspv-pool /dev/sdb
# Mayastor:要求最高,详见下一节
helm repo add openebs https://openebs.github.io/openebs && helm repo update
# 默认安装:Hostpath + LVM + ZFS + Replicated(Mayastor)
helm install openebs --namespace openebs openebs/openebs --create-namespace
# 只要本地卷,不装 Mayastor(推荐的轻量用法)
helm install openebs --namespace openebs openebs/openebs --create-namespace \
--set engines.replicated.mayastor.enabled=false
# 额外启用 Rawfile 引擎(默认关闭)
helm install openebs --namespace openebs openebs/openebs --create-namespace \
--set engines.local.rawfile.enabled=true
# 非标准发行版必须覆盖 kubelet 目录
# --set lvm-localpv.lvmNode.kubeletDir=/var/lib/k0s/kubelet/
# --set zfs-localpv.zfsNode.kubeletDir=/var/lib/k0s/kubelet/
# --set mayastor.csi.node.kubeletDir=/var/lib/k0s/kubelet/
kubectl get pods -n openebs && kubectl get storageclass
常见发行版的 kubelet 目录:标准 kubeadm 为 /var/lib/kubelet/,MicroK8s 为 /var/snap/microk8s/common/var/lib/kubelet/,k0s 为 /var/lib/k0s/kubelet/,RancherOS 为 /opt/rke/var/lib/kubelet/。
Mayastor 是唯一提供冗余的引擎,也是要求最高的一个:
# 1. 大页内存:每个存储节点预留 2GiB 的 2MiB 大页
echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
grep HugePages /proc/meminfo # 期望 HugePages_Total: 1024
echo "vm.nr_hugepages = 1024" | sudo tee -a /etc/sysctl.conf
# 2. 加载内核模块(高可用场景可启用 nvme_core.multipath=Y)
sudo modprobe nvme-tcp
# 3. 修改大页数量后必须重启 kubelet 或重启节点
sudo systemctl restart kubelet
# 4. 给存储节点打标签,Mayastor 只会调度到这些节点上
kubectl label node node1 openebs.io/engine=mayastor
lsblk -f # 5. 准备专用裸盘,不能有文件系统、不能被挂载
每个 io-engine 节点需要独占 2 个 CPU 核心与 1GiB 内存,并要求 CPU 支持 SSE4.2。涉及端口:10124(Mayastor gRPC)、8420 与 4421(NVMe-oF target),防火墙必须放行节点间通信。存储节点至少 3 个。
创建 DiskPool 把裸盘交给 Mayastor:
apiVersion: openebs.io/v1beta2
kind: DiskPool
metadata:
name: pool-on-node1
namespace: openebs
spec:
node: node1
disks:
- "aio:///dev/sdb" # 块设备写 /dev/sdb,文件用 aio:// 前缀
Hostpath 的类由 chart 自动创建,名字固定为 openebs-hostpath,provisioner 为 openebs.io/local。LVM 与 ZFS 的类需要自行创建(前提是节点上已建好 VG / pool):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: openebs-lvmpv
provisioner: local.csi.openebs.io
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
storage: "lvm"
volgroup: "lvmvg" # 或 vgpattern: "lvmvg.*"
fsType: "ext4"
thinProvision: "yes"
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: openebs-zfspv
provisioner: zfs.csi.openebs.io
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
poolname: "zfspv-pool"
fstype: "zfs" # 用 zfs 建 dataset,或填 ext4/xfs/btrfs 建 ZVOL
compression: "lz4"
recordsize: "128k"
Mayastor 的类在 DiskPool 就绪后由 chart 创建,名字形如 openebs-single-replica(provisioner io.openebs.csi-mayastor)。生产环境应另建多副本的类:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: mayastor-3
provisioner: io.openebs.csi-mayastor
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
repl: "3" # 副本数,不能超过 io-engine 节点数
protocol: "nvmf"
ioTimeout: "30"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
storageClassName: openebs-hostpath
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
helm repo update && helm get values openebs -n openebs > openebs-values.yaml
helm upgrade openebs openebs/openebs -n openebs -f openebs-values.yaml
kubectl -n openebs get pods -w && kubectl get diskpools -n openebs
kubectl get pvc -A | grep -E "openebs|mayastor" # 1. 确认数据不再需要
helm uninstall openebs -n openebs # 2. 卸载 chart
kubectl get crd | grep openebs | awk '{print $1}' | xargs kubectl delete crd # 3. 删 CRD
# 注意:这会连带删除所有 DiskPool 等自定义资源
# 4. 节点侧残留(危险,确认后再执行)
ls -l /var/openebs/local/ # Hostpath 数据
sudo vgs && sudo vgremove lvmvg # LVM 残留
sudo zpool destroy zfspv-pool # ZFS 残留
sudo wipefs -a /dev/sdb # Mayastor 磁盘残留
kubectl -n openebs get pods # 1. 各引擎的 Pod 是否都起来了
kubectl -n openebs get pods | grep -E "mayastor|lvm|zfs|localpv"
kubectl describe pvc app-data # 2. PVC 一直 Pending
kubectl -n openebs logs deploy/openebs-localpv-provisioner --tail=100
kubectl -n openebs logs deploy/openebs-lvm-localpv-controller --tail=100
kubectl -n openebs logs deploy/openebs-zfs-localpv-controller --tail=100
kubectl -n openebs get diskpools # 3. Mayastor 专用
kubectl -n openebs describe diskpool pool-on-node1
kubectl -n openebs logs daemonset/mayastor-io-engine --tail=100
grep HugePages /proc/meminfo && lsmod | grep -E "nvme_tcp|vfio" # 4. 大页与内核模块
kubectl get nodes -l openebs.io/engine=mayastor # 5. 节点标签
kubectl get storageclass 确认业务到底落在哪个类上。openebs-archive。它们不在新 chart 里,也不会有新修复。老集群可以继续跑,但新部署一律不要使用。nvme-tcp 内核模块与专用裸盘。磁盘上存在文件系统、分区表或 LVM 残留时 DiskPool 无法上线;内核模块没加载则卷无法挂载到业务节点。上线前用 lsblk -f 和 lsmod 逐节点确认。/var/openebs/local,数据不会随 Pod 迁移,节点故障即丢失 —— 与 local-path-provisioner 是同一类风险。它只是比裸 hostPath 多了动态供给与目录隔离。lvmvg 却写了 volgroup: lvmvg,PVC 只会一直 Pending。如果用了 vgpattern 而节点上没有匹配的 VG,同样静默失败。mayastor-etcd-localpv 与 mayastor-loki-localpv。这些是支撑用类,不要误设为集群默认类,更不要让业务 PVC 落到上面。kubeletDir。MicroK8s、k0s、RKE 等把 kubelet 目录放在非默认位置,不覆盖 lvm-localpv.lvmNode.kubeletDir 等参数,CSI node 插件会挂载到错误路径,卷挂载失败。allowVolumeExpansion。用错引擎会让「数据库磁盘不够了」变成一次停机迁移。volumeBindingMode: WaitForFirstConsumer。本地卷有节点拓扑约束,Immediate 会让 PV 在先于 Pod 调度时被创建到随机节点上,随后 Pod 无法挂载。kubectl — Kubernetes集群管理工具csi — OpenEBS 各引擎均以 CSI 驱动形式接入storageclass — 选择具体使用哪个 OpenEBS 引擎pvc — 向 OpenEBS 申请存储longhorn — 同为分布式块存储,提供更简单的副本方案rook — 功能更完整的分布式存储编排local-path-provisioner — 更轻量的本地目录供给器