K8s 系列 | 第 8 天:Volume 与 PersistentVolume:存储抽象层的核心机制


title: K8s 系列 | 第 8 天:Volume 与 PersistentVolume:存储抽象层的核心机制
tags:
– Kubernetes
– K8s系列
– DevOps
– 存储
– PersistentVolume
– Volume
– 容器存储


K8s 系列 | 第 8 天:Volume 与 PersistentVolume:存储抽象层的核心机制

第 8/30 天 | 本文约 2800 字 | 预计阅读时间 10 分钟

引言

在 Kubernetes 集群中运行有状态应用时,数据持久化是最核心的挑战之一。容器天生是无状态临时性的——Pod 重启、重建或迁移时,容器内部的文件系统会随之消失。然而,数据库、消息队列、文件存储等有状态应用需要数据在 Pod 生命周期之外持续存在。

K8s 通过 Volume(卷)PersistentVolume(持久卷,PV) 这两层抽象,构建了一套灵活、可扩展的存储体系。本文将深入剖析 Volume 与 PersistentVolume 的核心机制、使用场景以及生产最佳实践。


一、Volume:Pod 级别的临时与本地存储

1.1 为什么需要 Volume?

Volume 的核心作用是解耦数据与容器生命周期。即使容器崩溃重启,Volume 中的数据依然保留。Volume 的生命周期与 Pod 绑定——Pod 存在,Volume 就存在;Pod 被删除,Volume 也随之销毁(某些类型除外)。

1.2 常用 Volume 类型

类型 描述 适用场景
emptyDir Pod 创建时分配的空目录,随 Pod 删除而消失 临时缓存、多容器共享数据
hostPath 挂载宿主机文件系统到 Pod 单节点测试、DaemonSet 日志收集
configMap / secret 将配置/密钥挂载为文件 配置文件、敏感信息注入
nfs 网络文件系统 多节点共享存储
persistentVolumeClaim 动态/静态绑定 PV 生产环境最常用

1.3 emptyDir 实战:多容器共享数据

apiVersion: v1
kind: Pod
metadata:
  name: shared-volume-pod
spec:
  containers:
  - name: writer
    image: busybox
    command: ["sh", "-c", "echo 'Hello from writer' > /data/message.txt; sleep 3600"]
    volumeMounts:
    - name: shared-data
      mountPath: /data
  - name: reader
    image: busybox
    command: ["sh", "-c", "cat /data/message.txt; sleep 3600"]
    volumeMounts:
    - name: shared-data
      mountPath: /data
  volumes:
  - name: shared-data
    emptyDir: {}

注意emptyDir 默认使用节点本地磁盘(通常是 Docker 的 overlay 文件系统),也可以设置 medium: Memory 使用 tmpfs(RAM 加速)。


二、PersistentVolume(PV)与 PersistentVolumeClaim(PVC)

2.1 为什么需要 PV/PVC 抽象?

直接使用 hostPathnfs Volume 存在两个严重问题:

  1. 强耦合:Pod 的 YAML 中硬编码了存储的具体实现(哪个 NFS 服务器、哪个路径)
  2. 管理困难:存储需求和存储供给职责不分,运维人员需要修改应用 YAML

K8s 通过 PV(存储资源供给)PVC(存储资源需求) 的分离设计,实现了存储的声明式管理:

管理员 → 创建 PV(存储"池")
用户   → 创建 PVC(存储"需求")
K8s   → 自动将 PVC 绑定到匹配的 PV
Pod   → 通过 volumeMounts 使用 PVC

2.2 PV 的静态供给

管理员预先创建 PV 资源:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-001
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany       # 多个 Pod 同时读写
  persistentVolumeReclaimPolicy: Retain  # 释放后保留数据
  storageClassName: nfs-storage
  nfs:
    server: 192.168.1.100
    path: "/exports/k8s-data"

AccessModes 三种模式

模式 说明
ReadWriteOnce (RWO) 单节点读写(最常用,如块存储)
ReadOnlyMany (ROX) 多节点只读
ReadWriteMany (RWX) 多节点读写(如 NFS)

ReclaimPolicy 三种策略

策略 说明
Retain PVC 删除后 PV 保留,需手动清理
Delete PVC 删除后自动删除 PV 和后端存储(云存储常用)
Recycle (已废弃)执行 rm -rf 后重新可用

2.3 PVC 的使用

用户声明存储需求:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi       # 请求 5Gi,会绑定到 >=5Gi 的 PV
  storageClassName: nfs-storage

Pod 通过 PVC 引用存储:

apiVersion: v1
kind: Pod
metadata:
  name: mysql-pod
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "rootpass"
    volumeMounts:
    - name: mysql-data
      mountPath: /var/lib/mysql
  volumes:
  - name: mysql-data
    persistentVolumeClaim:
      claimName: data-claim

2.4 PV 绑定逻辑

PV 与 PVC 的绑定遵循以下匹配规则:

  1. 容量匹配:PV 的 capacity.storage >= PVC 的 resources.requests.storage
  2. 访问模式匹配:PV 的 accessModes 必须包含 PVC 要求的全部模式
  3. StorageClass 匹配storageClassName 必须一致(或 PVC 不指定类且 PV 没有类)
  4. 标签选择器:可选的 matchLabelsmatchExpressions 约束

每个 PVC 只能绑定一个 PV,一对一的绑定关系。


三、Pod 使用存储的完整流程

# 1. 创建 PV
kubectl apply -f pv-nfs-001.yaml

# 2. 创建 PVC
kubectl apply -f pvc-data-claim.yaml

# 3. 查看绑定状态
kubectl get pv
kubectl get pvc

# 4. 部署使用 PVC 的 Pod
kubectl apply -f mysql-pod.yaml

# 5. 验证数据持久化 - 删除 Pod 后重建
kubectl delete pod mysql-pod
kubectl apply -f mysql-pod.yaml   # 重建后数据仍然存在

四、常见问题与避坑指南

4.1 PVC 一直 Pending

kubectl describe pvc data-claim

典型原因:
– 没有任何 PV 满足容量或访问模式要求
– 没有配置动态存储供给(StorageClass + Provisioner)
– StorageClass 名称不匹配

4.2 hostPath 的局限性

# 不推荐生产使用!
volumes:
- name: data
  hostPath:
    path: /var/data
    type: DirectoryOrCreate

问题
– Pod 被调度到不同节点时数据丢失
– 多个 Pod 在同一个节点时可能写冲突
– 宿主机文件系统权限问题(Pod 用户与节点用户不匹配)

4.3 权限问题(fsGroup / securityContext)

MySQL、PostgreSQL 等数据库镜像通常以非 root 用户运行,写入挂载的 Volume 时可能遇到权限问题:

spec:
  securityContext:
    fsGroup: 999   # 与容器内用户 GID 一致
  containers:
  - name: mysql
    securityContext:
      runAsUser: 999
      runAsGroup: 999

4.4 PV 数据泄漏风险

persistentVolumeReclaimPolicy 设置为 Delete 时,删除 PVC 会同时删除后端存储数据!生产环境建议:

  • 重要数据:使用 Retain 策略
  • 开发测试:使用 Delete 策略自动清理
  • 定期备份 PV 数据

五、生产环境存储选型建议

存储类型 适用场景 性能 常用 Provisioner
NFS 多 Pod 共享读写、低成本 ⭐⭐⭐ nfs-client-provisioner
Ceph RBD 高性能块存储 ⭐⭐⭐⭐ csi-rbdplugin
CephFS 多 Pod 共享存储 ⭐⭐⭐⭐ csi-cephfsplugin
Longhorn 内置备份/灾备 ⭐⭐⭐ driver.longhorn.io
AWS EBS 云原生单节点读写 ⭐⭐⭐⭐⭐ ebs.csi.aws.com
Local SSD 极致性能、低延迟 ⭐⭐⭐⭐⭐ openebs.io/local

总结

概念 关键要点
Volume Pod 级别存储,emptyDir 适合缓存,hostPath 仅限测试
PV 集群资源,由管理员供给,独立于 Pod 存在
PVC 用户存储需求声明,自动与匹配的 PV 绑定
AccessModes RWO 单节点、ROX 只读、RWX 多节点并发
ReclaimPolicy Retain 保留、Delete 自动删除、Recycle 清理重用
生产建议 使用 StorageClass 动态供给,避免 hostPath,关注 fsGroup 权限

Volume 和 PersistentVolume 是 K8s 存储体系的基石。理解它们的核心机制后,下一篇文章我们将深入 StorageClass 与动态存储供给,带你实现”按需分配、用完即走”的自动化存储管理。


下期预告:K8s 系列 | 第 9 天:StorageClass 与动态存储供给实战 — 如何让 K8s 自动为你创建和销毁存储卷

系列目录:[K8s 系列 30 天从入门到生产运维](#)


本文为 K8s 系列第 8/30 篇,发布于 2026-06-24

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容