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 抽象?
直接使用 hostPath 或 nfs Volume 存在两个严重问题:
- 强耦合:Pod 的 YAML 中硬编码了存储的具体实现(哪个 NFS 服务器、哪个路径)
- 管理困难:存储需求和存储供给职责不分,运维人员需要修改应用 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 的绑定遵循以下匹配规则:
- 容量匹配:PV 的
capacity.storage >= PVC 的 resources.requests.storage - 访问模式匹配:PV 的
accessModes必须包含 PVC 要求的全部模式 - StorageClass 匹配:
storageClassName必须一致(或 PVC 不指定类且 PV 没有类) - 标签选择器:可选的
matchLabels和matchExpressions约束
每个 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















暂无评论内容