一、背景认知

1.1 云原生存储的核心意义

云原生存储是容器化应用数据持久化的基础,解决了容器 "无状态" 特性带来的数据丢失问题。与传统存储相比,它具有以下特点:

  • 生命周期独立:存储卷与 Pod 生命周期解耦,Pod 销毁重建后数据依然存在
  • 按需弹性扩展:支持动态创建和扩容存储卷,无需提前规划所有容量
  • 多类型支持:同时提供块、文件、对象三种存储模式,满足不同业务需求
  • 自动化管理:通过 Kubernetes API 统一管理存储资源,减少人工干预

1.2 三大存储类型对比与选型

这是云原生存储最基础也最重要的概念,必须先搞清楚:

特性块存储文件存储对象存储
核心比喻空白硬盘共享文件夹无限网盘 / 仓库
数据组织固定大小 "块"文件 + 目录树对象 (数据 + 元数据 + 唯一 ID)
访问接口磁盘扇区读写 (iSCSI)文件路径 (NFS/SMB)HTTP API(GET/PUT)
性能特点延迟极低 (微秒级),IOPS 高延迟中等 (毫秒级)高吞吐,适合顺序访问
扩展性纵向扩展为主横向扩展有上限近乎无限水平扩展
成本高中极低
云原生典型场景数据库 (MySQL/PostgreSQL)、消息队列 (Kafka)日志收集、配置文件共享、静态网站图片视频存储、备份归档、大数据分析

初学者必记口诀:

  • 数据库用块存储(性能第一)
  • 多 Pod 共享用文件存储(易用性第一)
  • 海量非结构化数据用对象存储(成本第一)

二、核心配置

2.1 物理磁盘选型标准

2.1.1 三种磁盘类型对比
磁盘类型接口典型 IOPS延迟容量范围成本适用场景
HDD (机械硬盘)SATA(6Gbps)/SAS(12Gbps)100-2005-10ms1-20TB最低备份、归档、冷数据存储
SATA SSDSATA(6Gbps)3000-100000.1-0.5ms120GB-8TB中等开发测试环境、轻量应用
NVMe SSDPCIe 3.0/4.010 万 - 100 万 +0.01-0.1ms256GB-16TB最高生产环境核心数据库、高性能计算

避坑提醒:绝对不要用 HDD 运行数据库!IOPS 不足会导致查询延迟超过 100ms,业务直接不可用

2.1.2 磁盘关键指标解读
  • IOPS:每秒读写操作次数,数据库、消息队列等随机读写密集型应用的核心指标
  • 吞吐量:每秒传输的数据量,视频、备份等顺序读写密集型应用的核心指标
  • 延迟:单次读写操作的响应时间,对用户体验影响最大
  • TBW:总写入字节数,衡量 SSD 寿命的关键指标,数值越大寿命越长

2.2 容量规划方法

通用公式:

总容量 = (当前数据量 × 1.3) + 快照备份空间 + 临时文件空间
  • 1.3 倍冗余:预留 30% 的缓冲空间,避免磁盘满导致系统崩溃
  • 快照备份:建议预留当前数据量的 20% 作为快照空间
  • 临时文件:日志、缓存等临时文件建议额外预留 30% 空间

不同业务类型参考:

  • 企业官网 / 个人博客:50-200GB SSD
  • 小型电商 / CRM 系统:500GB-2TB SSD
  • 视频 / 图片平台:10TB+ HDD 集群
  • 核心数据库:按每月 10-20% 的增长率预估 3 年需求

2.3 文件系统选择

云原生环境中最常用的两种文件系统:

文件系统特点适用场景
XFSRHEL/CentOS 默认,支持大文件,性能稳定,适合高并发生产环境数据盘、数据库存储
ext4兼容性好,工具丰富,适合小文件多的场景开发测试环境、日志存储

不推荐:NTFS、FAT32 等 Windows 文件系统,在 Linux 环境下性能和稳定性都较差

2.4 Kubernetes 存储核心概念

Kubernetes 通过三层抽象来管理存储资源:

  1. PV(PersistentVolume):集群中的一块持久化存储资源,由管理员预先创建
  2. PVC(PersistentVolumeClaim):Pod 对存储资源的 "申请单",描述需要的存储大小和访问模式
  3. StorageClass:定义存储的 "供货模板",支持动态创建 PV,无需管理员手动预分配

工作流程:

  1. 管理员创建 PV 或定义 StorageClass
  2. 用户创建 PVC 申请存储
  3. Kubernetes 自动匹配符合条件的 PV 或通过 StorageClass 动态创建 PV
  4. Pod 引用 PVC,将存储卷挂载到容器内

三、基础实操

3.1 Linux 服务器磁盘初始化(必学)

这是所有云原生存储的基础,无论使用哪种存储方案,都需要先掌握物理磁盘的基本操作。

3.1.1 步骤 1:查看系统磁盘信息
# 查看所有磁盘和分区
lsblk

# 查看详细信息(包括文件系统)
lsblk -f

# 查看挂载情况
df -TH

输出解读:

  • /dev/vda:通常是系统盘(虚拟机环境)
  • /dev/vdb、/dev/vdc等:通常是数据盘
  • /dev/nvme0n1:NVMe SSD 的命名方式
3.1.2 步骤 2:创建分区

注意:2TB 以下磁盘可以用fdisk,2TB 以上必须用parted(GPT 分区表)

方法一:fdisk(适用于 2TB 以下磁盘)

# 进入fdisk工具,操作/dev/vdb磁盘
fdisk /dev/vdb

# 交互式操作:
Command (m for help): n        # 创建新分区
Partition type: p              # 主分区(默认)
Partition number: 1            # 分区号(默认1)
First sector: 回车(默认)
Last sector: 回车(使用全部空间)
Command (m for help): w        # 写入分区表并退出

方法二:parted(适用于所有磁盘,推荐)

# 进入parted工具
parted /dev/vdb

# 交互式操作:
(parted) print                 # 查看当前分区表
(parted) mklabel gpt           # 创建GPT分区表(新磁盘必须执行)
(parted) mkpart primary xfs 0% 100%  # 创建一个使用全部空间的分区
(parted) print                 # 验证分区是否创建成功
(parted) quit                  # 退出
3.1.3 步骤 3:格式化分区
# 格式化为XFS(推荐生产环境使用)
mkfs.xfs /dev/vdb1

# 格式化为ext4
# mkfs.ext4 /dev/vdb1

高级格式化选项:

# XFS带卷标格式化
mkfs.xfs -L "DATA_DISK" /dev/vdb1

# ext4减少保留空间(默认保留5%,数据盘可以设为1%)
mkfs.ext4 -m 1 /dev/vdb1
3.1.4 步骤 4:挂载分区
# 创建挂载点目录
mkdir -p /mnt/data

# 临时挂载(重启后失效)
mount /dev/vdb1 /mnt/data

# 验证挂载
df -TH
3.1.5 步骤 5:配置开机自动挂载
# 备份fstab文件(重要!)
cp /etc/fstab /etc/fstab.bak

# 获取分区UUID(推荐使用UUID挂载,比设备名更稳定)
blkid /dev/vdb1

# 编辑fstab文件
vim /etc/fstab

# 添加以下内容(替换为你的UUID)
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/data xfs defaults 0 0

# 验证fstab配置是否正确(非常重要!错误会导致系统无法启动)
mount -a

# 如果没有报错,说明配置正确

挂载选项说明:

  • defaults:默认选项,包含 rw、suid、dev、exec、auto、nouser、async
  • noatime:不更新文件访问时间,提升性能
  • nofail:如果磁盘不存在,系统启动时不报错

3.2 Kubernetes 静态 PV/PVC 配置与使用

静态 PV 是最基础的 Kubernetes 存储方式,适合初学者理解存储工作原理。

3.2.1 准备工作

确保你有一个运行中的 Kubernetes 集群,并且已经在节点上完成了磁盘初始化(如上面的步骤)。

3.2.2 步骤 1:创建 HostPath 类型的 PV

HostPath 类型的 PV 将节点上的本地目录作为存储卷,适合单节点集群测试使用。

创建文件hostpath-pv.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: hostpath-pv-10gi
spec:
  capacity:
    storage: 10Gi  # PV容量
  accessModes:
    - ReadWriteOnce  # 只能被一个节点读写挂载
  persistentVolumeReclaimPolicy: Retain  # PVC释放后保留PV数据
  hostPath:
    path: /mnt/data/pv1  # 节点上的目录路径
    type: DirectoryOrCreate  # 如果目录不存在则创建

应用配置:

kubectl apply -f hostpath-pv.yaml

# 查看PV状态
kubectl get pv

输出应该显示 PV 状态为Available

3.2.3 步骤 2:创建 PVC 申请存储

创建文件hostpath-pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: hostpath-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi  # 申请5Gi存储
  # 不指定storageClassName,使用静态PV

应用配置:

kubectl apply -f hostpath-pvc.yaml

# 查看PVC状态
kubectl get pvc

输出应该显示 PVC 状态为Bound,表示已经成功绑定到 PV

3.2.4 步骤 3:在 Pod 中使用 PVC

创建文件nginx-with-pvc.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-with-pvc
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - name: data-volume
          mountPath: /usr/share/nginx/html  # 容器内挂载路径
      volumes:
      - name: data-volume
        persistentVolumeClaim:
          claimName: hostpath-pvc  # 引用上面创建的PVC

应用配置:

kubectl apply -f nginx-with-pvc.yaml

# 查看Pod状态
kubectl get pods
3.2.5 步骤 4:验证数据持久化
# 进入Pod,创建一个测试文件
kubectl exec -it $(kubectl get pods -l app=nginx -o name) -- sh
echo "Hello Kubernetes Storage!" > /usr/share/nginx/html/test.html
exit

# 删除Pod,Kubernetes会自动重建
kubectl delete pod $(kubectl get pods -l app=nginx -o name)

# 等待Pod重建完成后,再次进入查看文件是否存在
kubectl exec -it $(kubectl get pods -l app=nginx -o name) -- cat /usr/share/nginx/html/test.html

如果能看到 "Hello Kubernetes Storage!",说明数据持久化成功!

四、高阶用法

4.1 动态存储供应(StorageClass)

静态 PV 需要管理员手动创建,效率低下。StorageClass 实现了 PV 的动态创建,是生产环境的标准用法。

4.1.1 本地路径动态供应(Local Path Provisioner)

这是最简单的动态存储方案,适合单节点或小型集群使用。

安装步骤:

# 安装Local Path Provisioner
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.26/deploy/local-path-storage.yaml

# 查看StorageClass
kubectl get storageclass

设置为默认 StorageClass:

kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

使用示例:创建文件dynamic-pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  # 会自动使用默认的StorageClass

应用后,Kubernetes 会自动创建对应的 PV:

kubectl apply -f dynamic-pvc.yaml
kubectl get pv,pvc

4.2 本地持久卷(LocalVolume)

LocalVolume 直接使用节点上的本地磁盘,性能接近裸盘,适合高性能数据库等对 IO 要求极高的应用。

创建 LocalVolume PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-1
spec:
  capacity:
    storage: 100Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/nvme01  # 节点上的NVMe磁盘挂载点
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node-01  # 指定只能在node-01节点上使用

4.3 存储卷扩容

Kubernetes 支持在线扩容存储卷,无需停机。

前提条件:

  • StorageClass 必须开启allowVolumeExpansion: true
  • 底层存储支持扩容

扩容步骤:

# 编辑PVC,修改storage字段
kubectl patch pvc dynamic-pvc -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'

# 查看扩容状态
kubectl get pvc

4.4 存储快照与备份

存储快照可以快速创建存储卷的时间点备份,用于数据恢复和克隆。

创建快照:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: my-snapshot
spec:
  volumeSnapshotClassName: local-path-snapshot
  source:
    persistentVolumeClaimName: dynamic-pvc

从快照恢复:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: restored-pvc
spec:
  dataSource:
    name: my-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

五、拓展建议

5.1 性能调优最佳实践

  1. 磁盘层面:

    • 数据库等高性能应用优先使用 NVMe SSD
    • 开启磁盘写入缓存(注意断电保护)
    • 使用noatime挂载选项,减少不必要的 IO
  2. Kubernetes 层面:

    • 使用 LocalVolume 替代 HostPath,性能更好且更安全
    • 为不同性能需求的应用创建不同的 StorageClass
    • 避免在同一个节点上运行过多的 IO 密集型应用
  3. 应用层面:

    • 合理设置数据库连接池大小
    • 定期清理日志和临时文件
    • 将热点数据缓存到内存中

5.2 安全最佳实践

  1. 数据加密:

    • 开启存储卷静态加密
    • 敏感数据使用 Kubernetes Secrets 管理
    • 传输过程中使用 TLS 加密
  2. 访问控制:

    • 使用 RBAC 限制对存储资源的访问
    • 不要以 root 用户运行容器
    • 设置合适的文件权限

5.3 常见问题排查

  1. PVC 一直处于 Pending 状态:

    • 检查是否有匹配的 PV
    • 检查 StorageClass 是否存在且配置正确
    • 检查节点上是否有足够的存储空间
  2. Pod 无法挂载存储卷:

    • 检查节点上的目录是否存在且权限正确
    • 检查存储驱动是否正常运行
    • 查看 Pod 事件:kubectl describe pod <pod-name>
  3. 磁盘 IO 性能差:

    • 使用iostat、iotop等工具分析 IO 瓶颈
    • 检查是否有进程占用大量 IO
    • 考虑升级磁盘类型

5.4 学习资源推荐

  1. 官方文档:

  2. 书籍:

    • 《Kubernetes 权威指南》
    • 《Ceph 分布式存储实战》
  3. 开源项目:

    • Rook:Kubernetes 上的云原生存储编排器
    • Longhorn:轻量级分布式块存储
    • MinIO:高性能对象存储

更多推荐