跳到正文
复制成功
请遵守本站许可
报告
章节_文章 // 现场报告

文章编号: RL-POD存储管理

2026.07.29

Pod 存储管理

Chavy
Chavy
#Kubernetes#Pod#存储#PVC
档案

摘要:梳理 Volume、emptyDir、hostPath、PV、PVC 与 StorageClass,理解动态供给、访问模式、回收策略和 StatefulSet 的存储关联。

这一阶段学习 Kubernetes 如何让容器保存数据、共享文件,以及在 Pod 被删除或重新创建后继续使用原来的数据。

核心知识点:Volume、emptyDir、hostPath、PV、PVC、StorageClass、动态供给,以及 StatefulSet 的持久化存储。

一、为什么容器需要持久化存储?#

假设你部署了一个数据库容器:

flowchart TB
    N0["Pod"]
    N1["MySQL 容器"]
    N2["/var/lib/mysql"]
    N0 --> N1
    N1 --> N2

数据库把数据写入容器的可写层。当容器被删除并重新创建时,原来的容器可写层不会自动保留。

因此,数据库不能仅依赖容器自身的文件系统保存需要长期保留的数据。

Kubernetes 通过 Volume 将存储挂载到容器中。

flowchart TB
    N0["Pod<br/>MySQL 容器<br/>挂载路径:/var/lib/mysql"]
    N1["Volume<br/>把存储暴露给容器使用"]
    N2["实际存储<br/>节点磁盘、网络存储、云盘或分布式存储"]
    N0 -->|"Mount(挂载)"| N1
    N1 -->|"关联 / 使用"| N2

这里有一个关键概念:

Volume 是 Pod 使用存储的接口;它本身不一定意味着数据已经持久化到独立存储设备。

例如,emptyDir 通常只在 Pod 生命周期内保留数据,而持久卷可以在 Pod 替换后继续提供原有数据。


二、Volume:Pod 的存储卷#

Volume 是 Pod 层级的存储配置。一个 Pod 可以声明多个 Volume,并将它们挂载到一个或多个容器中。

1. emptyDir:临时共享目录#

emptyDir 在 Pod 被分配到节点后创建,Pod 在该节点上的生命周期内可以使用它。

典型用途:

  • 多个容器共享文件。
  • 保存临时缓存。
  • 存储中间计算结果。
  • 让 Sidecar 容器读取主容器产生的文件。

示例:

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: emptydir-demo
spec:
containers:
- name: writer
image: busybox:1.36
command: ["sh", "-c", "while true; do date >> /data/time.txt; sleep 5; done"]
volumeMounts:
- name: shared-data
mountPath: /data
- name: reader
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
emptyDir: {}

需要注意:

  • 同一个 Pod 内的容器可以共享这个目录。
  • 单纯重启容器时,emptyDir 通常仍然保留。
  • Pod 被删除后,emptyDir 的数据会随该 Pod 的生命周期结束而被清理。
  • 如果使用 emptyDir.medium: Memory,数据会存放在内存中,并计入相关内存资源管理。

因此,emptyDir 适合临时数据,不适合保存需要长期保留的数据库文件。

2. hostPath:直接挂载节点目录#

hostPath 将节点文件系统中的路径挂载到 Pod 内。

PRTCL // YAML
volumes:
- name: host-data
hostPath:
path: /data/app
type: DirectoryOrCreate

容器可以把这个卷挂载到 /app/data,实际数据位于当前 Node 的 /data/app。

它的主要风险是:

  • Pod 被调度到其他节点时,访问的可能是另一份目录。
  • 节点上的文件权限和目录内容可能影响容器运行。
  • 容器可能接触到节点的敏感文件。
  • 节点故障时,数据可能无法访问。

hostPath 常用于特定节点级应用、日志采集等场景,但不应简单地将它当作通用的生产持久化存储方案。


三、PV 与 PVC:把存储和应用解耦#

这是 Kubernetes 存储最核心的部分。

  • PV(PersistentVolume):集群中可供使用的持久卷资源。
  • PVC(PersistentVolumeClaim):应用对存储容量、访问模式等提出的申请。

可以把它理解为:

  • PV 是可供使用的存储资源。
  • PVC 是应用提交的存储申请。
  • Pod 通过 PVC 使用相应的存储。
flowchart TB
    N0["Pod<br/>容器通过 volumeMounts 挂载存储"]
    N1["PVC:存储申请<br/>申请 5Gi、指定访问模式等"]
    N2["PV:持久卷<br/>与符合条件的 PVC 绑定"]
    N3["底层存储<br/>例如网络文件系统、云盘或分布式存储"]
    N0 -->|"引用"| N1
    N1 <-->|"绑定"| N2
    N2 -->|"关联 / 使用"| N3

1. 创建一个静态 PV#

下面是一个教学示例,使用 hostPath 作为底层存储,适合单节点实验环境。

PRTCL // YAML
apiVersion: v1
kind: PersistentVolume
metadata:
name: demo-pv
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data/demo-pv
type: DirectoryOrCreate

说明:

  • capacity.storage:声明卷的容量。
  • accessModes:声明卷支持的访问模式。
  • storageClassName:指定存储类别。
  • persistentVolumeReclaimPolicy:定义 PVC 释放后 PV 的回收策略。
  • Retain:释放后保留底层存储资源,通常需要管理员手动处理。

重要: hostPath PV 只是教学示例,不具备自动跨节点迁移、数据复制或高可用能力。生产环境应选用符合业务要求的存储后端。

2. 创建 PVC#

PRTCL // YAML
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: demo-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual
resources:
requests:
storage: 1Gi

PVC 会申请一个容量至少满足需求、访问模式兼容且存储类别匹配的卷。

创建后查看:

PRTCL // BASH
Terminal window
kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
kubectl get pv
kubectl get pvc

正常情况下,符合条件的 PV 与 PVC 会绑定,状态显示为 Bound。

如果 PVC 一直处于 Pending,需要检查是否有合适的 PV、访问模式是否匹配、存储类别是否一致,以及容量是否满足要求。

3. 在 Pod 中使用 PVC#

PRTCL // YAML
apiVersion: v1
kind: Pod
metadata:
name: persistent-demo
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo hello > /data/hello.txt; sleep 3600"]
volumeMounts:
- name: app-data
mountPath: /data
volumes:
- name: app-data
persistentVolumeClaim:
claimName: demo-pvc

即使删除这个 Pod,再创建一个引用同一个 PVC 的 Pod,数据通常仍然可以保留,前提是底层存储没有被删除或损坏,且新 Pod 能够正常挂载该存储。


四、StorageClass:动态创建存储#

如果每个应用都要求管理员提前手动创建 PV,维护成本会很高。

StorageClass 用于描述一种存储类型,并可以与支持动态供给的存储插件配合,在 PVC 申请时自动创建底层存储卷。

例如:

flowchart TB
    N0["应用提交 PVC"]
    N1["指定 StorageClass"]
    N2["存储插件动态创建卷"]
    N3["PV 与 PVC 绑定"]
    N4["Pod 挂载存储"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N3 --> N4

常见配置:

PRTCL // YAML
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-storage
resources:
requests:
storage: 10Gi

这里的 fast-storage 只是示例名称,需要集群中存在对应的 StorageClass,并配置可用的存储供给程序。

查看集群存储类别:

PRTCL // BASH
Terminal window
kubectl get storageclass
kubectl get sc

注意:

  • 创建 StorageClass 对象本身不会自动实现存储功能。
  • 必须有兼容的动态供给程序和底层存储。
  • volumeBindingMode: WaitForFirstConsumer 可以让部分存储在考虑 Pod 调度位置后再进行绑定或供给。

五、访问模式与回收策略#

1. 访问模式#

模式含义
ReadWriteOnce(RWO)可由单个节点以读写方式挂载;同一节点上的多个 Pod 仍可能共享
ReadOnlyMany(ROX)可由多个节点只读挂载
ReadWriteMany(RWX)可由多个节点读写挂载
ReadWriteOncePod(RWOP)限制为单个 Pod 以读写方式使用卷,需满足相关 CSI 驱动与集群版本要求

这些是卷访问模式,不应简单理解为所有存储系统都能支持所有模式。实际支持范围取决于存储类型和驱动。

例如,普通云块存储经常支持 RWO,而共享文件存储可能支持 RWX。

2. 回收策略#

策略含义
RetainPVC 释放后保留 PV 和底层数据,通常需要人工清理
Delete支持该策略的动态供给插件通常会删除对应存储资源
Recycle旧式回收机制,已弃用,不应作为新方案使用

删除 PVC 不一定意味着底层数据一定会保留,也不一定意味着它一定会被删除。需要结合 PV 回收策略、StorageClass 配置和存储插件行为判断。


六、StatefulSet 为什么经常和存储一起出现?#

Deployment 适合大多数无状态应用,但数据库等有状态服务往往需要稳定的身份和独立的数据卷。

StatefulSet 可以为每个副本提供稳定的 Pod 身份,并通过 volumeClaimTemplates 为每个副本创建独立 PVC。

例如:

flowchart TB
    N0["StatefulSet: mysql"]
    N1["mysql-0"]
    N2["mysql-1"]
    N3["mysql-2"]
    N4["PVC: data-mysql-0"]
    N5["PVC: data-mysql-1"]
    N6["PVC: data-mysql-2"]
    N0 --> N1
    N0 --> N2
    N0 --> N3
    N1 --> N4
    N2 --> N5
    N3 --> N6

每个副本有独立的存储声明。Pod 被替换后,StatefulSet 可以重新创建对应的 Pod,并让它重新使用原来的 PVC。

但 StatefulSet 本身并不会自动实现数据库复制、数据备份、故障切换或数据一致性,这些仍需要数据库和存储系统配合。


七、存储机制要点#

  • emptyDir:适合 Pod 生命周期内的临时共享数据。
  • PV/PVC:分离存储资源与应用的存储需求。
  • StorageClass:定义存储类别,并可配合插件实现动态供给。
  • StatefulSet:提供稳定身份和每副本存储声明。
  • 持久化不等于高可用,也不等于备份。
归档于 2026.07.29
// 档案结束
Classified
章节_06
协议编号: CC-BY-NC-SA-4.0

Pod 存储管理

作者:Chavy发布日期:2026.07.29

基于 CC BY-NC-SA 4.0

© 2026 Chavy
Powered by Astro