K8s 静态持久化存储详解
在 Kubernetes(简称 K8s)集群中,容器本身的存储具有临时性,一旦容器删除或重启,内部数据会随之丢失。为实现数据持久化,K8s 提供了 Volume(存储卷) 机制,通过将容器内目录与底层存储资源挂载关联,确保数据长期保留。本文将详细介绍 K8s 静态存储中常用的 Volume 类型、使用流程及操作实践。
一、K8s 静态存储核心概念
1.1 静态存储定义
静态存储是指由集群管理员预先创建或配置底层存储资源(如本地目录、NFS 共享目录等),再通过 K8s 资源定义将其挂载到 Pod 中的存储方式。区别于动态存储(由 StorageClass 自动创建存储资源),静态存储的资源分配和管理需人工干预,适用于存储需求固定、资源可提前规划的场景。
1.2 常用 Volume 类型对比
不同 Volume 类型对应不同的底层存储机制,适用于不同业务场景,核心差异如下表所示:
| 类型 | 核心作用 | 数据生命周期 | 适用场景 |
|---|---|---|---|
| emptyDir | 提供 Pod 内临时目录 | 随 Pod 销毁而删除 | 容器间临时数据共享、缓存数据 |
| hostPath | 将宿主机目录挂载到容器内 | 独立于 Pod,宿主机目录长期保留 | 需持久化单节点数据(如日志存储) |
| NFS | 挂载远程 NFS 服务器共享目录 | 独立于 Pod 和节点,长期保留 | 多节点 Pod 共享数据(如静态资源) |
| PersistentVolumeClaim (PVC) | 基于 PersistentVolume (PV) 申请存储资源 | 与 PV 生命周期绑定,长期保留 | 生产环境中标准化存储申请流程 |
1.3 Volume 通用使用流程
无论使用哪种 Volume 类型,在 Pod 中挂载存储的核心流程一致,分为两步:
- 定义 Volume:在 Pod 的 spec.volumes 字段中声明存储卷,指定 Volume 类型及关联的底层资源(如 hostPath 路径、NFS 服务器地址等)。
- 容器挂载 Volume:在 Pod 的 spec.containers.volumeMounts 字段中,将已定义的 Volume 挂载到容器内的指定目录(mountPath)。
二、常用 Volume 类型实操指南
2.1 emptyDir:Pod 级临时存储
emptyDir 是最简单的 Volume 类型,本质是宿主机上为 Pod 临时创建的目录,Pod 删除后目录及数据会被自动清理,适用于临时数据存储场景(如容器间数据共享、临时缓存)。
2.1.1 创建 emptyDir 类型 Pod
- 编写 YAML 文件(emptydir.yaml),定义 Pod 及 emptyDir 存储卷:
apiVersion: v1
kind: Pod
metadata:name: pod-empty # Pod 名称
spec:containers:- name: container-empty # 容器名称image: nginx:1.25 # 基础镜像imagePullPolicy: IfNotPresent # 镜像拉取策略(本地有则不拉取)volumeMounts:- mountPath: /cache # 容器内挂载路径name: cache-volume # 关联的 Volume 名称(需与下方一致)volumes:- name: cache-volume # Volume 名称emptyDir: {} # 声明为 emptyDir 类型
- 执行命令创建 Pod:
[root@master1 yaml]# kubectl apply -f emptydir.yamlpod/pod-empty created
2.1.2 验证 emptyDir 存储效果
- 进入 Pod 内部,在挂载路径 /cache 下创建测试目录:
[root@master1 yaml]# kubectl exec -it pod-empty -- /bin/bashroot@pod-empty:/# cd /cacheroot@pod-empty:/cache# mkdir cache-test # 创建测试目录root@pod-empty:/cache# ls -altotal 0drwxrwxrwx 3 root root 24 Sep 27 02:58 .drwxr-xr-x 1 root root 52 Sep 27 02:52 ..drwxr-xr-x 2 root root 6 Sep 27 02:58 cache-test # 测试目录已创建
- 查看 Pod 调度节点及 UID(用于定位宿主机上的 emptyDir 实际路径):
# 查看 Pod 调度节点[root@master1 yaml]# kubectl get pods -o wide | grep emptypod-empty 1/1 Running 0 2m30s 10.244.102.98 node2 <none> <none># 查看 Pod UID[root@master1 yaml]# kubectl get pods pod-empty -o yaml | grep uiduid: cc47ce66-a887-4117-9f9f-d1ba389f88b3
- 登录调度节点(node2),查看 emptyDir 实际存储路径:
emptyDir 在宿主机的默认路径为 /var/lib/kubelet/pods//volumes/kubernetes.io~empty-dir/<Volume 名称>,可看到之前创建的 cache-test 目录:
[root@node2 pods]# tree cc47ce66-a887-4117-9f9f-d1ba389f88b3/volumes/kubernetes.io~empty-dir/cache-volumecc47ce66-a887-4117-9f9f-d1ba389f88b3/volumes/kubernetes.io~empty-dir/cache-volume└── cache-test # 之前在 Pod 内创建的测试目录
2.1.3 验证 Pod 删除后数据清理
删除 Pod 后,emptyDir 对应的宿主机目录会被自动删除:
# 删除 Pod[root@master1 yaml]# kubectl delete -f emptydir.yamlpod "pod-empty" deleted# 登录调度节点,确认目录已删除[root@node2 pods]# ls /var/lib/kubelet/pods/cc47ce66-a887-4117-9f9f-d1ba389f88b3ls: cannot access '/var/lib/kubelet/pods/cc47ce66-a887-4117-9f9f-d1ba389f88b3': No such file or directory
2.2 hostPath:宿主机目录挂载
hostPath 将 Pod 内目录与宿主机的指定目录挂载关联,即使 Pod 删除或重建,宿主机目录中的数据仍会保留。适用于需要在单节点内持久化数据的场景(如节点本地日志存储、单节点应用配置文件)。
2.2.1 hostPath 核心字段
| 字段 | 含义说明 | 是否必填 |
|---|---|---|
| path | 宿主机上的目录或文件路径(需确保路径格式正确,如 /data1) | 是 |
| type | 路径校验类型(可选):- Directory:宿主机必须已存在该目录- DirectoryOrCreate:目录不存在则自动创建- FileOrCreate:文件不存在则自动创建 | 否 |
2.2.2 创建 hostPath 类型 Pod
- 编写 YAML 文件(hostpath.yaml),定义双容器 Pod 并挂载 hostPath:
apiVersion: v1
kind: Pod
metadata:name: test-hostpath # Pod 名称
spec:containers:# 第一个容器(Nginx)- image: nginx:1.25imagePullPolicy: IfNotPresentname: test-nginxvolumeMounts:- mountPath: /test-nginx # 容器内挂载路径name: test-volume # 关联的 Volume 名称# 第二个容器(Tomcat)- image: tomcat:8.5-jre8-alpineimagePullPolicy: IfNotPresentname: test-tomcatvolumeMounts:- mountPath: /test-tomcat # 容器内挂载路径name: test-volume # 关联同一个 Volume(实现容器间数据共享)# 定义 hostPath 类型 Volumevolumes:- name: test-volumehostPath:path: /data1 # 宿主机路径type: DirectoryOrCreate # 目录不存在则自动创建
- 执行命令创建 Pod 并查看调度节点:
[root@master1 yaml]# kubectl apply -f hostpath.yamlpod/test-hostpath created# 查看 Pod 状态及调度节点[root@master1 yaml]# kubectl get pods test-hostpath -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATEStest-hostpath 2/2 Running 0 84s 10.244.102.99 node2 <none> <none>
2.2.3 验证 hostPath 数据持久化
- 登录调度节点(node2),确认宿主机目录已创建并添加测试目录:
[root@node2 ~]# cd /data1 # 宿主机挂载路径[root@node2 data1]# mkdir aa # 创建测试目录[root@node2 data1]# ls -altotal 0drwxr-xr-x 3 root root 16 Sep 27 11:22 .dr-xr-xr-x. 19 root root 269 Sep 27 11:19 ..drwxr-xr-x 2 root root 6 Sep 27 11:22 aa # 测试目录
- 进入两个容器,验证测试目录是否同步:
# 进入 Tomcat 容器[root@master1 yaml]# kubectl exec -it test-hostpath -c test-tomcat -- /bin/sh/usr/local/tomcat # cd /test-tomcat//test-tomcat # lsaa # 宿主机创建的测试目录已同步/test-tomcat # exit# 进入 Nginx 容器[root@master1 yaml]# kubectl exec -it test-hostpath -c test-nginx -- /bin/bashroot@test-hostpath:/# cd /test-nginx/root@test-hostpath:/test-nginx# lsaa # 测试目录同步(实现双容器数据共享)
- 验证 Pod 删除后数据保留:
删除 Pod 后,宿主机 /data1 目录及 aa 测试目录仍会保留:
# 删除 Pod[root@master1 yaml]# kubectl delete -f hostpath.yamlpod "test-hostpath" deleted# 登录宿主机查看目录[root@node2 data1]# ls -altotal 0drwxr-xr-x 3 root root 16 Sep 27 11:22 .dr-xr-xr-x. 19 root root 269 Sep 27 11:19 ..drwxr-xr-x 2 root root 6 Sep 27 11:22 aa # 数据未丢失
2.3 NFS:网络共享存储
NFS(Network File System,网络文件系统)是一种分布式存储协议,K8s 可通过 NFS 类型 Volume 将远程 NFS 服务器的共享目录挂载到 Pod 中。数据存储在 NFS 服务器上,独立于 Pod 和节点,适用于多节点 Pod 共享数据的场景(如静态网站资源、数据库备份)。
2.3.1 前提条件
需提前部署 NFS 服务器,并创建共享目录(如 /data/volumes),同时配置客户端(K8s 节点)可访问 NFS 服务器(通过 exports 文件授权)。
2.3.2 创建 NFS 类型 Pod
- 编写 YAML 文件(nfs.yaml),定义 Nginx Pod 并挂载 NFS 共享目录:
apiVersion: v1
kind: Pod
metadata:name: test-nfs-volume # Pod 名称
spec:containers:- name: test-nfsimage: nginx:1.25imagePullPolicy: IfNotPresentports:- containerPort: 80 # Nginx 默认端口protocol: TCPvolumeMounts:- name: nfs-volumes # 关联的 Volume 名称mountPath: /usr/share/nginx/html # Nginx 网页根目录(挂载后替换为 NFS 目录)# 定义 NFS 类型 Volumevolumes:- name: nfs-volumesnfs:path: /data/volumes # NFS 服务器共享目录server: 192.168.197.181 # NFS 服务器 IP 地址
- 执行命令创建 Pod 并查看状态:
[root@master1 yaml]# kubectl apply -f nfs.yamlpod/test-nfs-volume created# 查看 Pod 状态及 IP[root@master1 yaml]# kubectl get pods -o wide | grep test-nfs-volumetest-nfs-volume 1/1 Running 0 74s 10.244.102.100 node2 <none> <none>
2.3.3 验证 NFS 数据同步
- 在 NFS 服务器共享目录下创建测试文件:
# 登录 NFS 服务器(192.168.197.181)[root@master1 ~]# cd /data/volumes/[root@master1 volumes]# vi index.html # 创建 Nginx 测试页面[root@master1 volumes]# cat index.htmlHello # 页面内容
- 验证 Pod 内文件同步:
通过 Pod IP 访问 Nginx 服务,或直接进入容器查看文件,确认 NFS 目录内容已同步:
# 访问 Pod IP(验证 Nginx 页面)[root@master1 volumes]# curl 10.244.102.100Hello # 与 NFS 服务器上的 index.html 内容一致# 进入 Pod 查看文件[root@master1 volumes]# kubectl exec -it test-nfs-volume -- /bin/bashroot@test-nfs-volume:/# cat /usr/share/nginx/html/index.htmlHello # 内容同步
2.4 PV & PVC:标准化存储申请
在生产环境中,直接使用 NFS 或 hostPath 存在管理成本高、权限控制复杂的问题。K8s 引入 PV(PersistentVolume,持久卷) 和 PVC(PersistentVolumeClaim,持久卷声明) 机制,将存储资源与 Pod 解耦:
- PV:由集群管理员创建,代表底层实际存储资源(如 NFS 目录、云盘),包含存储容量、访问模式、回收策略等属性。
- PVC:由开发人员创建,代表 Pod 对存储的需求(如容量、访问模式),K8s 会自动匹配满足条件的 PV 并绑定,实现 “按需申请”。
