在 Kubernetes 中,Pod 本身是无状态的,容器一旦重启或被调度到新节点,原有数据就会丢失。为了保证数据的持久化和共享,K8s 提供了 Volume 机制。
Volume 的类型非常多,但在日常实践中,最常用的就是几类:emptyDir、hostPath、本地 PV、NFS 静态 PV、以及基于 NFS 的动态卷。
这篇文章我会把这几种方式一次讲清楚,并结合配置示例,帮你快速上手
1、使用 emptyDir(最简单的临时存储)
emptyDir 是最常用也最简单的 Volume 类型,它会在 Pod 启动时创建一个空目录,Pod 删除时目录也会被清空。适用于 临时缓存、日志文件 等场景。
配置示例:
volumes:
-name:jar-vol
emptyDir: {}
containers:
-name:app
image:myapp:v1
volumeMounts:
-name:jar-vol
mountPath:/var/app/
-name:logs
mountPath: /home/listen/Apps/logs📌 特点:
目录生命周期与 Pod 一致。
容器重启不会丢,但 Pod 删除就没了。
适合临时文件或缓存。
2、使用 hostPath(挂载宿主机目录)
有时我们希望容器能直接访问节点上的目录或文件,这时可以用 hostPath。
volumes:
- name: logs
hostPath:
path: /logs/
type: DirectoryOrCreate📌 特点:
可以直接访问宿主机的目录。
Pod 重启数据不会丢失,但如果 Pod 被调度到另一台节点,就找不到数据。
适合调试环境,生产中需谨慎使用。
3、使用本地静态 PV(local PersistentVolume)
相比直接用 hostPath,本地 PV 是更推荐的方式。它会将节点本地存储抽象成 PV 供 Pod 绑定,结合 PVC 使用。
apiVersion: v1
kind:PersistentVolume
metadata:
name:local-pv
spec:
persistentVolumeReclaimPolicy:Retain
capacity:
storage:10Gi
accessModes:
-ReadWriteOnce
storageClassName:local-storage
local:
path:/mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
-matchExpressions:
-key:kubernetes.io/hostname
operator:In
values:
- node1📌 特点:
数据绑定到节点,持久化效果比 hostPath 更规范。
仍然存在 Pod 跨节点无法访问数据的问题。
4、Pod 直接挂载 NFS(最简 NFS 方式)
如果你有一台 NFS 服务器,可以直接把它挂到 Pod 上使用。
volumes:
- name: nfs
nfs:
path: /nfs
server: 192.168.x.x
readOnly: false📌 特点:
最快的 NFS 使用方式,直接挂载即可。
适合快速实验或低复杂度应用。
但没有 PVC 绑定,灵活性差,管理性不足。
5、使用 NFS 静态 PV(更规范的 NFS 挂载)
在生产环境中,推荐通过 PV + PVC 的方式挂载 NFS。
1)定义 StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: manual-nfs-storage
provisioner: kubernetes.io/no-provisioner2)定义 PV:
apiVersion: v1
kind:PersistentVolume
metadata:
name:nfs-pv001
spec:
capacity:
storage:1Gi
accessModes:
-ReadWriteMany
storageClassName:manual-nfs-storage
nfs:
path:/nfs
server:192.x.x.x3)定义 PVC:
apiVersion: v1
kind:PersistentVolumeClaim
metadata:
name:nfs-pvc001
namespace:kube-ops
spec:
accessModes:
-ReadWriteMany
resources:
requests:
storage:1Gi
storageClassName: manual-nfs-storage4)Pod 挂载 PVC:
volumes:
- name: nfs-pv001
persistentVolumeClaim:
claimName: nfs-pvc001📌 特点:
更加规范,支持多 Pod 共享数据。
管理上比直接挂载 NFS 要好。
6、使用 NFS-Subdir-External-Provisioner(动态卷)
nfs-subdir-external-provisioner 能在已有的 NFS 共享上按需动态创建子目录并把它包装成 PV,应用直接创建 PVC 即可得到 PV,不用手工预先创建 PV。适合:多租户、共享存储(ReadWriteMany)、希望对 NFS 自动化管理的场景。
步骤大致如下:
1)创建 ServiceAccount + RBAC 权限(确保能操作 PV、PVC、endpoints)。
2)部署 nfs-subdir-external-provisioner,指定 NFS 服务器和路径。
3)创建默认 StorageClass,让 PVC 自动使用它。
apiVersion: storage.k8s.io/v1
kind:StorageClass
metadata:
name:default-nfs-storageclass
annotations:
storageclass.kubernetes.io/is-default-class:"true"# 如果你想设为默认类(可选)
provisioner:nfs-subdir-external-provisioner # 必须和 Deployment 中的 PROVISIONER_NAME 一致
reclaimPolicy:Delete
volumeBindingMode:Immediate
# 可选 mountOptions
#mountOptions:
# - vers=3
# - noresvport小建议:如果集群中还有其他 StorageClass,不要随意把它设为默认;生产环境中更常见的是显式在 PVC 中写 storageClassName。
4)定义 PVC 即可自动生成对应的 NFS 子目录。
pvc-test.yaml 示例:
apiVersion: v1
kind:PersistentVolumeClaim
metadata:
name:auto-pv-with-nfs-client-provisioner
namespace:default
spec:
storageClassName:default-nfs-storageclass
accessModes:
-ReadWriteMany
resources:
requests:
storage: 1Mipod-test.yaml 示例:
apiVersion: v1
kind:Pod
metadata:
name:pod-touch-cfs
namespace:default
spec:
restartPolicy:Never
containers:
-name:test-pod
image:busybox
command: ["/bin/sh", "-c", "echo hello > /mnt/hello.txt && ls -la /mnt && sleep 300"]
volumeMounts:
-name:nfs-pvc
mountPath:/mnt
volumes:
-name:nfs-pvc
persistentVolumeClaim:
claimName: auto-pv-with-nfs-client-provisioner📌 特点:
真正的动态卷,无需手动创建 PV。
非常适合多租户、多应用环境。
管理性和扩展性最强,是生产推荐方案。
总结
在 Kubernetes 中,Volume 的使用场景大致可以这么选:
emptyDir → 临时缓存、日志目录。
hostPath → 调试环境快速挂载宿主机目录,不推荐生产使用。
local PV → 节点绑定存储,更规范的宿主机卷。
NFS 直接挂载 → 简单快速,但不够灵活。
NFS 静态 PV → 规范化持久化,支持多 Pod。
NFS 动态卷(推荐) → 自动管理,最适合生产环境。
一句话:测试用 emptyDir/hostPath,生产建议走 PV/PVC,最好结合 NFS 动态卷。