Kubernetes 本地存储实战:Open-Local 从部署到生产级应用

背景与痛点

在云原生时代,有状态应用(如数据库、消息队列、缓存系统)对存储性能有着极高的要求。传统的网络存储方案虽然提供了便利的共享能力,但往往面临以下挑战:

  • 延迟问题 │ 网络 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(独占盘类型) 支持 不支持 不支持 支持 不支持 不支持 支持
  1. 用户创建带有PVC的StatefulSet。
  2. PvController调用External Provisioner来创建PV,本地存储未创建真实的lv。
  3. 调度带有PVC的Pod时,kube-scheduler调用extender注册的接口,根据存储情况确定创建lv的节点。
  4. PvController完成PVC和PV的延迟绑定后,kube-scheduler完成调度Pod。
  5. 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

# 重新连接查询(数据应保留)
相关推荐
IT利刃出鞘5 小时前
Docker Compose--解决容器时间不正确的问题
运维·docker·容器
eight *7 小时前
docker部署elk+filebeat日志收集分析系统
elk·docker·容器
小股虫8 小时前
分布式事务:在增长中台,我们如何做到“发出去的内容”和“记录的数据”不打架?
分布式·微服务·云原生·架构·团队建设·方法论
自己的九又四分之三站台9 小时前
docker安装pgvector、age和postgis
运维·docker·容器
忧郁蓝调269 小时前
Redis不停机数据迁移:基于 redis-shake 的跨实例 / 跨集群同步方案
运维·数据库·redis·阿里云·缓存·云原生·paas
java1234_小锋9 小时前
ZooKeeper集群中服务器之间是怎样通信的?
分布式·zookeeper·云原生
幺零九零零10 小时前
Docker底层-IPC Namespace(进程间通信隔离)
运维·docker·容器
easy_coder10 小时前
从“未知故障”到“自治诊断”:基于双路召回与RAG的智能诊断系统构建
人工智能·云原生·云计算
eddy-原11 小时前
ELKStack 与 Kubernetes 核心基础知识点综合作业
云原生·容器·kubernetes