背景与痛点
在云原生时代,有状态应用(如数据库、消息队列、缓存系统)对存储性能有着极高的要求。传统的网络存储方案虽然提供了便利的共享能力,但往往面临以下挑战:
- 延迟问题 │ 网络 I/O 引入额外延迟,影响实时性应用
- 成本高昂 │ 高性能网络存储设备价格昂贵
- 单点瓶颈 │ 网络带宽可能成为性能瓶颈
- 管理复杂 │ 本地磁盘缺乏统一管理和调度能力
为了解决以上的痛点,经过测试和综合考虑,使用更为简单的open-local作为数据存储管理
open-local介绍
Open-Local是由多个组件构成的本地磁盘管理系统,目标是解决当前 Kubernetes 本地存储能力缺失问题。通过Open-Local,使用本地存储会像集中式存储 一样简单。
目前 open-local 支持以下存储特性: 本地存储池管理、存储卷动态分配、存储调度算法扩展、存储卷扩容、存储卷快照、存储卷监控、存储卷 IO 限流、原生块设备及临时卷。
Open-Local包含四大类组件:
- Scheduler-Extender: 作为 Kubernetes Scheduler 的扩展组件,通过 Extender 方式实现,新增本地存储调度算法
- CSI: 按照 CSI(Container Storage Interface) 标准实现本地磁盘管理能力
- Agent: 运行在集群中的每个节点,根据配置清单初始化存储设备,并通过上报集群中本地存储设备信息以供 Scheduler-Extender 决策调度
- Controller: 获取集群存储初始化配置,并向运行在各个节点的 Agent 下发详细的配置清单
open-local 包含两个 CRD
1、NodeLocalStorage: open-local 通过 NodeLocalStorage 资源上报每个节点上的存储设备信息,该资源由 controller 创建,由每个节点的 agent 组件更新其 status。该 CRD 属于全局范围的资源。
2、NodeLocalStorageInitConfig: open-local controller 可通过 NodeLocalStorageInitConfig 资源创建每个 NodeLocalStorage 资源。NodeLocalStorageInitConfig 资源中包含全局默认节点配置和特定节点配置,若节点的 node label 满足表达式则使用特定节点配置,否则使用默认配置
支持的存储类型
| 存储类型 | StorageClass 名称 | 适用场景 |
|---|---|---|
| LVM | open-local-lvm |
通用场景,支持动态扩容和快照 |
| LVM 直写 | open-local-lvm-xfs |
高性能场景,XFS 文件系统 |
| 裸设备 | open-local-device |
数据库等需要直接访问磁盘的场景 |
| 临时卷 | open-local-lvm-ephemeral |
临时数据存储 |
Open-Local支持两种类型本地磁盘的使用:
- LVM: 共享盘类型 ,即通过 LVM 方式管理存储设备。当在 K8s 中创建 PV 资源时,
Open-Local会从对应 VolumeGroup 中创建 LogicalVolume 来代表该PV。 - Device: 独占盘类型,即一个 PV 一个块设备。这里块设备可以是一整块磁盘,也可以是一个分区。
不同类型 PV 所支持的存储能力也不同。
| 类型 | 动态分配 | PV扩容 | PV快照 | 原生块设备 | IO限流 | 临时卷 | 监控数据 |
|---|---|---|---|---|---|---|---|
| LVM(共享盘类型) | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
| Device(独占盘类型) | 支持 | 不支持 | 不支持 | 支持 | 不支持 | 不支持 | 支持 |

- 用户创建带有PVC的StatefulSet。
- PvController调用External Provisioner来创建PV,本地存储未创建真实的lv。
- 调度带有PVC的Pod时,kube-scheduler调用extender注册的接口,根据存储情况确定创建lv的节点。
- PvController完成PVC和PV的延迟绑定后,kube-scheduler完成调度Pod。
- kubelet拉起Pod时,csi创建lv,把lv挂载到PV卷目录,相当于完成了attach+mount。kubelet再把PV卷目录挂载到容器目录。
环境准备
| 组件 | 最低版本 | 推荐版本 | 说明 |
|---|---|---|---|
| Kubernetes | v1.20 | v1.24+ | 需开启 CSI |
| Helm | v3.0 | v3.8+ | 用于包管理 |
| Linux 发行版 | - | RHEL/CentOS 7+, Ubuntu 18.04+ | 需 LVM2 |
| 空闲块设备 | - | 每个节点至少 1 块 | 用于存储池 |
安装 LVM2
bash
# Red Hat/CentOS
sudo yum install -y lvm2
# Debian/Ubuntu
sudo apt-get install -y lvm2
# 验证安装
lvm version
准备空闲块设备
bash
# 查看可用磁盘(确保未使用)
lsblk
# 示例输出:
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
# sda 8:0 0 100G 0 disk
# ├─sda1 8:1 0 50G 0 part /
# ├─sda2 8:2 0 50G 0 part [SWAP]
# sdb 8:16 0 50G 0 disk ← 目标设备,未挂载
# 重要:确保设备未被使用(无文件系统、无挂载点)
sudo wipefs -a /dev/sdb # 清除残留签名(可选)
节点标签(可选)
bash
# 为节点打标签,便于后续管理
kubectl label node <node-name> open-local=enabled
部署 open-local
下载 Helm Chart
bash
# 克隆官方仓库
git clone https://github.com/alibaba/open-local.git
cd open-local
# 或直接使用 Helm 仓库(推荐)
helm repo add open-local https://alibaba.github.io/open-local
helm repo update
配置 Helm Values
编辑 helm/values.yaml 或创建自定义配置文件:
bash
# values-custom.yaml
# values-production.yaml
name: open-local
namespace: open-local # 推荐独立命名空间
driver: local.csi.aliyun.com # 可保持官方,或改为 csi.open-local.io
images:
local:
image: registry.cn-hangzhou.aliyuncs.com/open-local/open-local
tag: v0.8.0
registrar:
image: registry.cn-hangzhou.aliyuncs.com/open-local/csi-node-driver-registrar
tag: v2.9.0
provisioner:
image: registry.cn-hangzhou.aliyuncs.com/open-local/csi-provisioner
tag: v3.5.0
resizer:
image: registry.cn-hangzhou.aliyuncs.com/open-local/csi-resizer
tag: v1.9.0
snapshotter:
image: registry.cn-hangzhou.aliyuncs.com/open-local/csi-snapshotter
tag: v6.3.0
snapshot_controller:
image: registry.cn-hangzhou.aliyuncs.com/open-local/snapshot-controller
tag: v6.3.0
agent:
name: open-local-agent
device: /dev/sdb # 必须根据实际修改!
kubelet_dir: /var/lib/kubelet
volume_name_prefix: local
spdk: false
driverMode: all # 完整功能
max_volumes_per_node: 256
extender:
name: open-local-scheduler-extender
strategy: spread # 生产环境高可用
port: 23000
init_job: true
controller:
update_nls: "true"
storageclass:
lvm:
enabled: true
name: open-local-lvm
parameters:
volumeType: "LVM"
csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
# 按需启用其他 SC
lvm_xfs:
enabled: true # 数据库场景推荐
name: open-local-lvm-xfs
parameters:
volumeType: LVM
csi.storage.k8s.io/fstype: xfs
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
# 禁用不需要的 SC
lvm_throttle:
enabled: false
device_ssd:
enabled: false
device_hdd:
enabled: false
monitor:
enabled: true # 生产环境建议开启
namespace: monitoring # 你的监控命名空间
global:
RegistryURL: registry.cn-hangzhou.aliyuncs.com/open-local # 国内镜像源
ImagePullPolicy: Always
配置说明:
agent.device:必须修改,指定节点上的空闲块设备- 多节点差异化配置 :如果节点设备不同,可通过
nodeSelector或 Helm 的--set参数实现
部署安装
bash
# 使用推荐配置
helm install open-local open-local/open-local \
-n open-local \
--create-namespace \
-f values-production.yaml
# 验证
kubectl get po -n open-local
kubectl get sc
验证安装
bash
# 查看所有组件(应在 kube-system 或 open-local 命名空间)
kubectl get po -n open-local
# 预期输出(所有 Pod 应为 Running/Completed):
NAME READY STATUS RESTARTS AGE
open-local-agent-6zmkb 3/3 Running 0 28s
open-local-csi-provisioner-6dbb7c459c-mcp9l 1/1 Running 0 28s
open-local-csi-resizer-57cfd85df7-x44zg 1/1 Running 0 28s
open-local-csi-snapshotter-689b6bbcfc-wwc57 1/1 Running 0 28s
open-local-init-job-2wvbs 0/1 Completed 0 28s
open-local-init-job-bw8nh 0/1 Completed 0 28s
open-local-init-job-frdxp 0/1 Completed 0 28s
open-local-scheduler-extender-7d5cf688b6-pr426 1/1 Running 0 28s
open-local-snapshot-controller-d6f78754-czfnw 1/1 Running 0 28s
关键组件说明:
- open-local-agent:节点代理,负责磁盘初始化和卷管理
- open-local-csi-provisioner:CSI 动态供给器
- open-local-scheduler-extender:调度器扩展,确保 Pod 与存储节点绑定
- open-local-init-job:初始化任务,每个节点一个,完成 LVM 卷组创建
验证存储池
bash
# 查看节点上的 LVM 卷组(在任意节点执行)
sudo vgs
# 预期输出:
# VG #PV #LV #SN Attr VSize VFree
# open-local-pool-0 1 0 0 wz--n- <50.00g <50.00g
# 查看详细信息
sudo vgdisplay open-local-pool-0
检查 CRD 和 StorageClass
bash
# 查看 CRD
kubectl get crd | grep open-local
# 查看 StorageClass(应自动创建)
kubectl get sc
# 预期输出:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
open-local-lvm csi.open-local.io Delete WaitForFirstConsumer true 5m
LVM实现挂载
LVM 核心概念
bash
物理磁盘 (Physical Disk)
↓
物理卷 (PV - Physical Volume) → pvcreate
↓
卷组 (VG - Volume Group) → vgcreate
↓
逻辑卷 (LV - Logical Volume) → lvcreate
↓
文件系统 (Filesystem) → mkfs
↓
挂载点 (Mount Point) → mount
手动操作示例(理解 open-local 底层)
bash
# 假设设备为 /dev/sdc2(一个分区)
# 1. 创建物理卷(PV)
sudo pvcreate /dev/sdc2
# 输出:Physical volume "/dev/sdc2" successfully created.
# 2. 创建卷组(VG),命名为 s2
sudo vgcreate s2 /dev/sdc2
# 输出:Volume group "s2" successfully created
# 3. 创建逻辑卷(LV),1GB 大小,命名为 lv_test
sudo lvcreate --size 1G --name lv_test s2
# 输出:Logical volume "lv_test" created.
# 4. 格式化为 ext4 文件系统
sudo mkfs.ext4 /dev/s2/lv_test
# 5. 创建挂载点并挂载
sudo mkdir -p /apps/a
sudo mount /dev/s2/lv_test /apps/a
# 6. 验证挂载
df -h | grep lv_test
# 输出:/dev/mapper/s2-lv_test 1014M 1.3M 951M 1% /apps/a
# 7. 卸载(清理)
sudo umount /apps/a
sudo lvremove s2/lv_test
sudo vgremove s2
sudo pvremove /dev/sdc2
open-local 自动化了上述 1-3 步 ,你只需提供设备,它会自动创建 open-local-pool-0 VG。
创建 StorageClass
bash
# sc-lvm.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: open-local-lvm
provisioner: csi.open-local.io
parameters:
type: lvm # 存储类型
volumeType: "xfs" # 文件系统
pool: "open-local-pool-0" # 存储池名称
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer # 关键:延迟绑定
kubectl apply -f sc-lvm.yaml
部署 MySQL 应用
bash
# mysql-app.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data
spec:
storageClassName: open-local-lvm
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: "password123"
- name: MYSQL_DATABASE
value: "testdb"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
volumes:
- name: data
persistentVolumeClaim:
claimName: mysql-data
验证数据持久性
bash
# 进入 MySQL 创建数据
kubectl exec -it $(kubectl get pod -l app=mysql -o jsonpath='{.items[0].metadata.name}') -- mysql -uroot -ppassword123
# 在 MySQL 中执行:
# CREATE DATABASE test;
# USE test;
# CREATE TABLE users (id INT, name VARCHAR(20));
# INSERT INTO users VALUES (1, 'open-local');
# SELECT * FROM users;
# 重启 Pod 验证数据
kubectl rollout restart deployment/mysql
# 重新连接查询(数据应保留)