Kubernetes 存储完全指南(适用于 Kubernetes v1.35)
Kubernetes 存储完全指南(适用于 Kubernetes v1.35)
文档说明
- 适用版本:Kubernetes v1.35.4
- 前置知识:了解 Pod 的基本概念
- 目标:从零掌握 Kubernetes 存储体系,包括 emptyDir、hostPath、PV、PVC、StorageClass 的原理与使用
第一章:为什么需要 Kubernetes 存储?
容器本身是无状态的——当 Pod 被删除或重新调度到其他节点时,容器内的所有数据都会丢失。这对于需要持久化存储的应用(如数据库、消息队列、文件存储)是不可接受的。
Kubernetes 提供了完善的存储解决方案,让应用数据可以独立于 Pod 生命周期而存在:
| 存储类型 | 生命周期 | 适用场景 |
|---|---|---|
| emptyDir | 与 Pod 生命周期相同 | 临时缓存、同 Pod 容器间共享数据 |
| hostPath | 与节点生命周期相同 | 访问宿主机文件、调试 |
| PV / PVC | 独立于 Pod 生命周期 | 持久化存储(数据库、消息队列等) |
| StorageClass | 集群级别 | 动态自动创建 PV |
第二章:emptyDir —— 临时存储
2.1 什么是 emptyDir?
emptyDir 是 Kubernetes 中最简单的存储卷类型。当 Pod 被调度到节点上时,会在节点上创建一个空目录,该目录在 Pod 的整个生命周期内存在。
生命周期:emptyDir 的生命周期与 Pod 完全绑定——Pod 删除,数据随之删除。
2.2 核心特性
| 特性 | 说明 |
|---|---|
| 创建时机 | Pod 被调度到节点时自动创建 |
| 初始状态 | 空目录 |
| 数据持久性 | 仅存在于 Pod 运行期间 |
| 容器共享 | 同一个 Pod 中的多个容器可以共享同一个 emptyDir |
| 存储介质 | 默认使用节点磁盘,可指定 medium: Memory 使用内存(tmpfs) |
2.3 适用场景
- 同一 Pod 内多个容器之间的数据共享(如 Sidecar 容器读取主容器的日志)
- 应用程序的临时缓存或暂存空间(scratch space)
- 计算过程中的中间文件存储
2.4 YAML 示例
apiVersion: v1
kind: Pod
metadata:
name: emptydir-demo
spec:
containers:
- name: writer
image: busybox
command: ['sh', '-c', 'echo "hello" > /cache/data.txt && sleep 3600']
volumeMounts:
- name: cache-volume
mountPath: /cache
- name: reader
image: busybox
command: ['sh', '-c', 'sleep 3600']
volumeMounts:
- name: cache-volume
mountPath: /shared
volumes:
- name: cache-volume
emptyDir: {} # 空配置即可
2.5 使用内存作为存储介质
volumes:
- name: memory-volume
emptyDir:
medium: Memory # 使用 tmpfs(内存文件系统)
sizeLimit: 256Mi # 限制大小(v1.8+)
注意:使用
medium: Memory时,数据存储在内存中,读写速度极快,但 Pod 重启或节点重启后数据会丢失,且受节点内存容量限制。
第三章:hostPath —— 宿主机存储
3.1 什么是 hostPath?
hostPath 卷能将宿主机节点文件系统上的文件或目录挂载到 Pod 中。
生命周期:hostPath 的数据独立于 Pod 生命周期——Pod 删除后,宿主机上的数据依然存在。
3.2 核心特性
| 特性 | 说明 |
|---|---|
| 数据持久性 | 数据存在于节点本地,Pod 删除不影响 |
| 节点绑定 | 数据与特定节点绑定,Pod 调度到其他节点无法访问 |
| 使用场景 | 访问宿主机文件(如 Docker socket)、节点监控、调试 |
3.3 ⚠️ 安全风险
hostPath 存在严重的安全风险:
- Pod 可以读写宿主机敏感目录(如
/、/etc、/var) - 可能导致宿主机文件系统被破坏
- 可能泄露宿主机敏感信息
最佳实践:
- 尽可能避免使用 hostPath
- 如果必须使用,限制范围到所需的文件或目录
- 以只读方式挂载
- 使用 PodSecurityPolicy 或 Pod Security Standards 限制 hostPath 的使用
3.4 YAML 示例
apiVersion: v1
kind: Pod
metadata:
name: hostpath-demo
spec:
containers:
- name: test-container
image: busybox
command: ['sh', '-c', 'sleep 3600']
volumeMounts:
- name: host-volume
mountPath: /host-data
readOnly: true # 以只读方式挂载,降低风险
volumes:
- name: host-volume
hostPath:
path: /var/log # 宿主机路径
type: Directory # 可选:检查路径类型
3.5 hostPath 的 type 字段
| type | 说明 |
|---|---|
""(空) | 不做任何检查 |
DirectoryOrCreate | 如果目录不存在则创建(权限 0755) |
Directory | 目录必须存在 |
FileOrCreate | 如果文件不存在则创建(权限 0644) |
File | 文件必须存在 |
Socket | UNIX socket 必须存在 |
CharDevice | 字符设备必须存在 |
BlockDevice | 块设备必须存在 |
第四章:PV 与 PVC —— 持久化存储的基石
4.1 为什么需要 PV 和 PVC?
emptyDir 和 hostPath 都有明显局限:
emptyDir:数据随 Pod 删除而消失hostPath:数据绑定到特定节点,Pod 迁移后无法访问
为了解决这些问题,Kubernetes 引入了 PV(PersistentVolume) 和 PVC(PersistentVolumeClaim) 。
4.2 核心概念
PV(PersistentVolume,持久卷) 是集群中的一块存储资源,由管理员事先制备或通过 StorageClass 动态制备。PV 是集群级别的资源,独立于任何 Pod 的生命周期。
PVC(PersistentVolumeClaim,持久卷声明) 是用户对存储的请求。Pod 会消耗节点资源,而 PVC 会消耗 PV 资源。
核心设计思想:PV 和 PVC 将存储的“供应” 与存储的“使用” 解耦。用户只需声明需要多大的存储、什么访问模式,无需关心底层存储的具体实现。
4.3 PV 的关键字段
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 10Gi # 存储容量
accessModes:
- ReadWriteMany # 访问模式
persistentVolumeReclaimPolicy: Retain # 回收策略
storageClassName: standard # 存储类名称
# 以下是具体存储类型配置(二选一)
nfs: # NFS 存储
server: nfs-server.example.com
path: /exports
# 或 hostPath(仅用于测试)
# hostPath:
# path: /data/pv
4.4 PVC 的关键字段
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
namespace: default
spec:
accessModes:
- ReadWriteOnce # 访问模式
resources:
requests:
storage: 5Gi # 请求的存储大小
storageClassName: standard # 存储类名称(用于匹配 PV)
4.5 访问模式(Access Modes)
| 访问模式 | 说明 | 适用场景 |
|---|---|---|
| ReadWriteOnce(RWO) | 单个节点可读写 | 大多数应用(数据库等) |
| ReadOnlyMany(ROX) | 多个节点可只读 | 共享只读数据(配置文件) |
| ReadWriteMany(RWX) | 多个节点可读写 | 共享文件系统(NFS) |
| ReadWriteOncePod(RWOP) | 单个 Pod 可读写(v1.27+) | 需要独占存储的 Pod |
4.6 回收策略(Reclaim Policy)
| 策略 | 说明 |
|---|---|
| Retain | 保留数据,需管理员手动清理 |
| Delete | 删除 PV 时同时删除底层存储(默认) |
| Recycle | 已弃用,执行 rm -rf 后重新可用 |
4.7 PV 的生命周期
PV 和 PVC 的交互遵循以下生命周期:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 制备 │ ──▶ │ 绑定 │ ──▶ │ 使用 │ ──▶ │ 回收 │
│Provisioning │ │ Binding │ │ Using │ │ Reclaiming │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
阶段一:制备(Provisioning)
PV 的制备有两种方式:
静态制备(Static Provisioning) :集群管理员手动创建一批 PV 卷。这些 PV 对象存在于 Kubernetes API 中,可供用户使用。
动态制备(Dynamic Provisioning) :当静态 PV 无法匹配 PVC 时,集群可以自动创建新的 PV。基于 StorageClass 实现。
阶段二:绑定(Binding)
当用户创建 PVC 时,Kubernetes 的 PV Controller 会持续监听 API Server,发现处于待绑定状态的 PVC 后,尝试将其与满足条件的 PV 进行绑定。
绑定条件:
- 存储容量 ≥ PVC 请求的大小
- 访问模式匹配
- StorageClass 名称匹配(如果指定)
如果找不到匹配的 PV,PVC 将保持 Pending 状态,直到有合适的 PV 可用。
阶段三:使用(Using)
Pod 通过引用 PVC 来使用存储:
apiVersion: v1
kind: Pod
metadata:
name: pvc-demo
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: pvc-example # 引用 PVC
阶段四:回收(Reclaiming)
当 PVC 被删除后,PV 根据回收策略决定如何处理:
- Retain:PV 状态变为
Released,数据保留,需管理员手动清理 - Delete:PV 和底层存储一起被删除
第五章:StorageClass —— 动态存储的核心
5.1 为什么需要 StorageClass?
静态制备存在明显问题:
- 管理负担重:管理员需要提前创建各种大小、访问模式的 PV
- 资源浪费:提前创建的 PV 可能长时间不被使用
- 难以匹配:用户请求的 PVC 可能找不到完全匹配的 PV
- 沟通成本高:用户需要了解可用的 PV 类型
StorageClass 解决了这些问题——它让存储可以按需自动创建。
5.2 StorageClass 是什么?
StorageClass 是 Kubernetes 中用于描述存储类别的 API 对象。它为管理员提供了描述不同存储类型的方法。
一句话理解:StorageClass 是存储的“配置模板”——当用户创建 PVC 并指定 StorageClass 时,Kubernetes 会根据这个模板自动创建对应的 PV 和底层存储。
5.3 StorageClass 的核心字段
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
annotations:
storageclass.kubernetes.io/is-default-class: "false" # 是否为默认存储类
provisioner: kubernetes.io/aws-ebs # 制备器(必须)
parameters: # 制备器参数
type: gp2
fsType: ext4
reclaimPolicy: Retain # 回收策略(默认 Delete)
allowVolumeExpansion: true # 是否允许卷扩容
volumeBindingMode: WaitForFirstConsumer # 卷绑定模式
mountOptions: # 挂载选项
- discard
5.4 核心字段详解
provisioner(制备器)—— 最重要的字段
每个 StorageClass 必须指定一个制备器(Provisioner),它决定了使用哪个卷插件来创建 PV。
内置制备器(名称以 kubernetes.io 为前缀):
| 制备器 | 说明 |
|---|---|
kubernetes.io/aws-ebs | AWS EBS 块存储 |
kubernetes.io/gce-pd | GCE 持久化磁盘 |
kubernetes.io/azure-disk | Azure 磁盘 |
kubernetes.io/azure-file | Azure 文件存储 |
kubernetes.io/vsphere-volume | vSphere 存储 |
kubernetes.io/cinder | OpenStack Cinder |
外部制备器:也支持使用外部制备器(如 CSI 驱动),名称由用户自定义。例如华为云的 nas.csi.everest.io。
parameters(参数)
parameters 是传递给制备器的具体参数,不同制备器支持的参数不同。
示例(AWS EBS):
parameters:
type: gp3 # 磁盘类型(gp2/gp3/io1)
fsType: ext4 # 文件系统类型
iopsPerGB: "10" # 每 GB 的 IOPS(io1 专用)
示例(GCE PD):
# "slow" 存储类 —— 标准磁盘
parameters:
type: pd-standard
# "fast" 存储类 —— SSD 磁盘
parameters:
type: pd-ssd
reclaimPolicy(回收策略)
指定由该 StorageClass 动态创建的 PV 的回收策略:
Delete(默认):PVC 删除时,PV 和底层存储一起删除Retain:PVC 删除时,PV 和数据保留,需手动处理
volumeBindingMode(卷绑定模式)
控制 PV 的创建和绑定时机:
| 模式 | 说明 |
|---|---|
Immediate(默认) | PVC 创建后立即创建 PV 并绑定 |
WaitForFirstConsumer | 等到第一个使用该 PVC 的 Pod 被调度时才创建 PV |
为什么需要
WaitForFirstConsumer? 某些存储(如本地存储)与特定节点绑定,如果提前创建 PV 但 Pod 被调度到其他节点,会导致无法挂载。WaitForFirstConsumer确保 PV 在 Pod 确定调度节点后才创建,避免这个问题。
allowVolumeExpansion(允许扩容)
设置为 true 时,允许在 PVC 创建后在线扩容存储容量。
5.5 默认 StorageClass
可以将某个 StorageClass 标记为集群的默认存储类。当 PVC 没有指定 storageClassName 时,会自动使用默认的 StorageClass。
标记为默认:
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: "true"
注意:集群中只能有一个默认 StorageClass。如果存在多个默认 StorageClass,Kubernetes 会使用最近创建的那个。
第六章:StorageClass 工作原理深度解析
6.1 动态存储供应的完整流程
当用户创建了一个指定 storageClassName 的 PVC 时,背后发生了什么?
用户创建 PVC(指定 storageClassName)
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 1. API Server 接收 PVC 请求,存入 etcd │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 2. PV Controller(在 Controller Manager 中)监听新 PVC │
│ 发现 PVC 指定了 StorageClass,但没有匹配的 PV │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 3. PV Controller 调用 StorageClass 中指定的 Provisioner │
│ 传入 parameters 中的配置参数 │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 4. Provisioner 与底层存储系统 API 交互 │
│ 在存储系统中创建实际的存储卷(如云盘、NFS 导出等) │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 5. Provisioner 返回存储卷信息,PV Controller 创建 PV 对象 │
│ PV 包含存储卷的访问信息(如云盘 ID、NFS 地址等) │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 6. PV Controller 将 PV 与 PVC 绑定 │
│ PVC 状态变为 Bound │
└───────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────┐
│ 7. Pod 通过 PVC 使用存储 │
│ Kubelet 将存储卷挂载到 Pod 的容器中 │
└───────────────────────────────────────────────────────────────┘
6.2 关键组件职责
| 组件 | 职责 |
|---|---|
| API Server | 接收并存储 PVC、StorageClass 等资源对象 |
| PV Controller(在 Controller Manager 中) | 管理 PV/PVC 生命周期,包括静态绑定和触发动态供应 |
| Provisioner(制备器) | 与底层存储系统交互,实际创建存储卷 |
| Scheduler | 确保 Pod 被调度到能够访问 PV 的节点上 |
| Kubelet | 将存储卷挂载到 Pod 的容器中 |
6.3 静态制备 vs 动态制备
| 对比维度 | 静态制备 | 动态制备(StorageClass) |
|---|---|---|
| PV 创建方式 | 管理员手动创建 | 系统自动创建 |
| 存储资源 | 提前分配,可能浪费 | 按需分配,无浪费 |
| 管理成本 | 高 | 低 |
| 响应速度 | 立即可用 | 需等待存储创建(通常几秒到几分钟) |
| 适用场景 | 小规模集群、测试环境 | 生产环境、大规模集群 |
第七章:完整实战示例
7.1 场景:部署一个使用持久化存储的 MySQL
Step 1:创建 StorageClass(使用本地存储模拟,仅测试用)
注意:生产环境应使用云厂商或 NFS 等网络存储。
# storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-storage
provisioner: kubernetes.io/no-provisioner # 本地存储无制备器
volumeBindingMode: WaitForFirstConsumer
Step 2:创建 PV(静态制备)
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: fast-storage
hostPath: # 仅用于测试,生产环境使用网络存储
path: /data/mysql
Step 3:创建 PVC
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: fast-storage
Step 4:创建 Deployment 使用 PVC
# deployment.yaml
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: "password"
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
Step 5:部署
kubectl apply -f storageclass.yaml
kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
kubectl apply -f deployment.yaml
Step 6:验证
# 查看 PV 状态
kubectl get pv
# 查看 PVC 状态(应为 Bound)
kubectl get pvc
# 查看 Pod
kubectl get pods
# 验证数据持久化:删除 Pod 后重新创建,数据依然存在
kubectl delete pod mysql-xxx
kubectl get pods # 新 Pod 自动创建
第八章:故障排查
8.1 常见问题与解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| PVC 一直 Pending | 没有匹配的 PV | 检查 StorageClass 名称、容量、访问模式是否匹配 |
| PVC 一直 Pending | StorageClass 不存在 | 检查 StorageClass 是否存在:kubectl get sc |
| Pod 无法启动 | PVC 未绑定 | 检查 PVC 状态,确保 Bound |
| Pod 无法启动 | 节点无法访问存储 | 检查网络存储是否可达,防火墙规则 |
| 数据丢失 | 使用了 emptyDir 或错误的回收策略 | 确认存储类型,检查 reclaimPolicy |
8.2 调试命令
# 查看所有 PV
kubectl get pv
# 查看所有 PVC
kubectl get pvc -A
# 查看 PVC 详情(含事件)
kubectl describe pvc <pvc-name>
# 查看 PV 详情
kubectl describe pv <pv-name>
# 查看 StorageClass
kubectl get storageclass
# 查看 StorageClass 详情
kubectl describe storageclass <sc-name>
第九章:最佳实践总结
9.1 存储类型选择指南
| 场景 | 推荐存储类型 |
|---|---|
| 临时缓存、同 Pod 容器共享数据 | emptyDir |
| 调试、访问宿主机文件 | hostPath(谨慎使用) |
| 生产环境持久化存储(数据库等) | PV + PVC + StorageClass(动态制备) |
| 共享文件系统(多 Pod 读写) | NFS + PV + PVC |
| 云上生产环境 | 云厂商 CSI 驱动 + StorageClass |
9.2 通用最佳实践
- 生产环境使用动态制备(StorageClass):减少管理成本,按需分配资源
- 合理设置回收策略:重要数据使用
Retain,临时数据使用Delete - 使用
WaitForFirstConsumer绑定模式:避免存储与节点不匹配的问题 - 监控存储使用情况:防止存储空间耗尽
- 定期备份重要数据:PV 不是备份方案
- 避免使用 hostPath:除非确有需要,且务必限制访问范围
- 为 StorageClass 设置默认值:提升用户体验
附录:快速索引
| 需求 | 命令/配置 |
|---|---|
| 查看所有 PV | kubectl get pv |
| 查看所有 PVC | kubectl get pvc -A |
| 查看 StorageClass | kubectl get storageclass |
| 查看 PVC 详情 | kubectl describe pvc <name> |
| 创建 StorageClass | kubectl apply -f storageclass.yaml |
| 创建 PV | kubectl apply -f pv.yaml |
| 创建 PVC | kubectl apply -f pvc.yaml |
| 设置默认 StorageClass | storageclass.kubernetes.io/is-default-class: "true" |
| emptyDir 配置 | emptyDir: {} |
| emptyDir 使用内存 | emptyDir: { medium: Memory } |
| hostPath 配置 | hostPath: { path: /host/path } |
第十章:NFS 实战 —— 在 Kubernetes 中使用 NFS 存储
10.1 环境准备:搭建 NFS 服务器
首先,我们需要一台独立的 NFS 服务器(可以是虚拟机或物理机),为 Kubernetes 集群提供存储能力。
第一步:安装 NFS 服务端
以 Ubuntu 22.04 为例:
# 更新系统并安装 NFS 服务端
sudo apt update
sudo apt install -y nfs-kernel-server
第二步:创建共享目录
创建一个目录用于存储 Kubernetes 的持久化数据:
# 创建共享目录
sudo mkdir -p /data/k8s-storage
# 修改权限,允许容器内的进程写入
sudo chown nobody:nogroup /data/k8s-storage
sudo chmod 777 /data/k8s-storage
参数说明:
chmod 777是为所有用户开放读写执行权限。在生产环境中,你应根据实际的安全策略进行更精细的权限控制。
第三步:配置 NFS 共享
编辑 /etc/exports 文件,定义共享目录和访问权限:
sudo vim /etc/exports
添加以下内容(请将 192.168.1.0/24 替换为你的 Kubernetes 节点所在网段):
/data/k8s-storage 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
关键参数说明:
rw:客户端对该目录拥有读写权限。sync:同步写入,保证数据一致性。no_subtree_check:禁用子树检查,提升性能。no_root_squash:允许客户端的 root 用户保留 root 权限,这对于容器内进程以 root 身份运行至关重要。
第四步:启动并验证 NFS 服务
# 重新加载 exports 配置
sudo exportfs -ra
# 重启 NFS 服务
sudo systemctl restart nfs-kernel-server
# 设置开机自启
sudo systemctl enable nfs-kernel-server
# 验证共享目录是否已导出
sudo exportfs -v
第五步:在所有 Kubernetes 节点上安装 NFS 客户端
为了让每个节点都能挂载 NFS 存储,需要在所有节点(包括 master 和 worker)上安装 NFS 客户端工具。
# Ubuntu/Debian
sudo apt install -y nfs-common
# CentOS/RHEL
sudo yum install -y nfs-utils
第六步:验证节点与 NFS 服务器的连接
在任意一个 Kubernetes 节点上执行以下命令,测试是否能正确看到 NFS 服务端共享的目录:
# 查看 NFS 服务器共享的目录(请替换为你的 NFS 服务器 IP)
showmount -e 192.168.1.10
如果一切正常,你应该能看到 /data/k8s-storage。
10.2 静态制备:手动创建 PV 和 PVC
这是最直接的方式,由管理员提前创建好 PV。
10.2.1 创建 PV (PersistentVolume)
创建一个 nfs-pv.yaml 文件:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 10Gi # PV 的总容量
accessModes:
- ReadWriteMany # 支持多节点同时读写
persistentVolumeReclaimPolicy: Retain # 回收策略:保留数据
storageClassName: "" # 空字符串表示不使用 StorageClass
nfs: # 指定后端为 NFS
path: /data/k8s-storage # NFS 服务器上的共享目录
server: 192.168.1.10 # NFS 服务器的 IP 地址
应用此配置:
kubectl apply -f nfs-pv.yaml
查看 PV 状态:
kubectl get pv
10.2.2 创建 PVC (PersistentVolumeClaim)
创建一个 nfs-pvc.yaml 文件:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany # 访问模式必须与 PV 匹配
resources:
requests:
storage: 5Gi # 请求 5Gi 存储
storageClassName: "" # 静态制备,留空
应用此配置:
kubectl apply -f nfs-pvc.yaml
查看 PVC 状态,确认已与 PV 绑定(状态为 Bound):
kubectl get pvc
10.2.3 在 Pod 中使用 PVC
创建一个 nginx-pod.yaml 文件,将 NFS 存储挂载到 /usr/share/nginx/html 目录:
apiVersion: v1
kind: Pod
metadata:
name: nginx-nfs-pod
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: nfs-storage
mountPath: /usr/share/nginx/html # 容器内的挂载路径
volumes:
- name: nfs-storage
persistentVolumeClaim:
claimName: nfs-pvc # 引用上面创建的 PVC
应用此配置:
kubectl apply -f nginx-pod.yaml
验证 Pod 是否正常运行,并检查挂载是否成功。
10.3 动态制备:使用 NFS Provisioner(推荐方案)
静态制备需要手动管理 PV,在大规模集群中维护成本较高。动态制备通过 StorageClass 和 Provisioner 实现存储的按需自动创建,是生产环境更推荐的方案。
10.3.1 核心原理
动态制备的核心是 NFS Subdir External Provisioner。它的工作流程如下:
- 用户创建 PVC 时,指定一个关联了 NFS Provisioner 的 StorageClass。
- Provisioner 监听到 PVC 的创建请求。
- Provisioner 在 NFS 服务器的共享目录下,自动创建一个以
命名空间-PVC名称-随机串命名的子目录。 - Provisioner 自动创建一个 PV,指向这个新的 NFS 子目录。
- Kubernetes 将这个新 PV 与 PVC 绑定。
这样,用户只需要创建 PVC,无需关心 PV 的细节,实现了存储的“按需分配”。
10.3.2 部署 NFS Provisioner
官方推荐使用 Helm 进行部署。
第一步:添加 Helm 仓库并更新
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update
第二步:安装 Provisioner
执行以下命令进行安装(请将 nfs.server 和 nfs.path 替换为你的实际信息):
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.1.10 \
--set nfs.path=/data/k8s-storage \
--set storageClass.defaultClass=true \
--set storageClass.name=nfs-storage
参数说明:
nfs.server:你的 NFS 服务器 IP 地址。nfs.path:NFS 服务器上的共享目录。storageClass.defaultClass=true:将新创建的 StorageClass 设置为集群默认存储类。storageClass.name=nfs-storage:指定 StorageClass 的名称为nfs-storage。可选参数:
- 可以通过
--set storageClass.archiveOnDelete=true来控制 PVC 删除时,其对应的 NFS 子目录是归档(重命名)还是直接删除。
10.3.3 使用动态 PVC
部署完成后,你只需创建 PVC 并指定 storageClassName: nfs-storage 即可。
创建一个 dynamic-pvc.yaml 文件:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-nfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: nfs-storage # 指定我们刚创建的 StorageClass
应用此配置:
kubectl apply -f dynamic-pvc.yaml
查看 PVC,你会发现它自动进入了 Bound 状态,并且自动创建了一个对应的 PV。
kubectl get pvc
kubectl get pv
你可以在 NFS 服务器的 /data/k8s-storage 目录下看到 Provisioner 自动创建的子目录。
文档版本:v1.0
适用环境:Kubernetes v1.35+
前置条件:已部署 Kubernetes 集群并配置kubectl
更多推荐
所有评论(0)