Kubernetes 存储管理:EmptyDir、hostPath

Kubernetes 存储管理:EmptyDir、hostPath

_

Recycle回收策略依靠专用回收Pod清理存储文件,该Pod运行依赖debian-base:bookworm-v1.0.4镜像。集群若无外网访问权限,会出现镜像拉取失败问题,可通过云链接离线下载镜像包,手动导入集群节点使用。

链接: https://pan.baidu.com/s/17IhaH9O5cF3GzlcjZZDDRg?pwd=dtbn

提取码: dtbn

一、EmptyDir

1. Volume

Container内部文件仅仅临时存储,一旦容器重启或异常崩溃,所有修改内容都会重置、数据安全丢失。即便kubelet重启容器,容器也会恢复至初始纯净状态。同时,业务场景中还存在多Pod之间共享文件的需求。为此,Kubernetes抽象出Volume存储卷组件,统一解决容器重启数据持久化与Pod间文件共享等问题。

Kubernetes提供种类丰富的存储卷类型,覆盖多类场景:分布式存储(NFS、CephFS)、公有云专属块存储(awsElasticBlockStore、azureDisk)、集群内置卷(EmptyDir、ConfigMap、hostPath)以及ISCSI、FC等企业级存储协议。

[Step1] 使用存储卷时,在“.spec.volumes”字段中设置为Pod提供的卷。

spec:
  volumes:b

[Step2] 同时在“.spec.containers[*].volumeMounts”字段中声明存储卷在容器中的挂载位置。

spec:
  containers:
    - image: centos
      volumeMounts:

2. EmptyDir定义

EmptyDir,全称EmptyDir Persistent Volume(临时非持久卷)。EmptyDir是k8s最简单的临时挂载卷,Pod调度至指定节点后,系统会自动创建EmptyDir卷。

该卷的生命周期与节点上运行的Pod绑定内存。顾名思义,卷的初始状态为空。同一Pod内多个容器可以各自挂载该卷的不同的或相同路径,彼此之间能够读写共享卷内的文件。一旦Pod被移除出当前节点,EmptyDir内所有数据会被永久清除。

容器崩溃时不会触发Pod从节点剥离,因此容器崩溃阶段EmptyDir卷内的数据能够完整保留,不会丢失。可以借助“sizeLimit”字段约束EmptyDir卷的可用空间上限。容量单位区分两种换算标准:

  • 厂商存储标注标准:“M”和“G”采用十进制

  • 磁盘配额标准:“Mi”和“Gi”采用二进制

EmptyDir本地路径格式为:

/var/lib/kubelet/pods/[Pod的UID]/volumes/kubernetes.io~empty-dir/[存储卷名称]

2.1 生命周期

  1. Pod创建 → 节点创建空白目录

  2. Pod正常/异常删除 → 目录及目录数据立即彻底清空销毁

  3. 同一个Pod内多个容器可以共享同一个EmptyDir

2.2 核心特点

数据存储在宿主机磁盘,无法跨节点访问。若Pod调度漂移到其他节点,会重新生成全新空白目录。EmptyDir卷不具备持久化能力,Pod重启后数据全部丢失。EmptyDir开箱即用,无需预先部署存储资源。同时支持内存模式配置“medium: Memory”,数据置于内存读写,访问数据更快。但Pod重启数据同样清空,且会占用容器内存配额。

2.3 典型用途

  • 同一Pod内多容器文件交换,如sidecar日志采集、文件同步

  • 应用临时缓存、运行时的临时文件

  • 内存高速临时读写场景

二、hostPath

1. hostPath定义

hostPath,全称Host Path Volume(主机路径卷)。hostPath卷可以将宿主机文件系统中的文件或目录挂载至Pod内。常见使用场景:容器需要调用节点Docker引擎、系统预置程序等节点本地资源。但是生产环境中尽量减少hostPath的使用,该卷会把Pod绑定至固定节点,大幅降低Pod跨节点调度迁移的灵活性。

在生产环境中并非完全不可以使用hostPath,存在折中使用方案:在宿主机挂载NFS共享目录,再通过hostPath将本地挂载点映射给Pod。依托NFS的跨节点共享能力,可以解决原生hostPath切换节点后数据丢失问题。

2.1 生命周期

数据独立于Pod:Pod删除后,宿主机上的文件/目录依然保留,数据不会清除。Pod重建在同一节点可以复用旧数据,调度到其他节点则看不到原节点文件。

2.2 核心特点

hostPath卷强绑定单个宿主机节点,数据无法在多节点间共享;文件权限、归属用户完全依托宿主机原有配置。安全隐患突出,容器可直接读写宿主机本地文件,若发生容器逃逸,攻击者能篡改宿主机系统关键文件。同时hostPath支持多类资源校验类型,可区分目录、普通文件、套接字、字符设备等对象。

2.3 典型用途

  • 节点级系统日志收集,如挂载“/var/log”

  • 部署监控、Agent组件读取宿主机内核、系统文件

  • 本地老旧程序迁移,需要固定宿主机目录

  • 本地存储单机持久化,不推荐生产多节点集群

2. hostPath类型

创建hostPath卷时必须配置对应的type类型。如果类型配置错误或宿主机上不存在对应资源,如指定目录不存在。Kubernetes会中止Pod创建流程,Pod会长时间卡在“ContainerCreating”状态无法正常启动。

type取值

对应行为

(空)

type的默认值,空字符串用于向后兼容,意味着在安装hostPath卷前不会执行任何检查

DirectoryOrCreate

如果在给定路径上什么都不存在,自动创建空目录。权限设置为0755,属主和属组与kubelet一致

Directory

在给定路径上必须存在的目录,校验不通过则Pod创建失败

fileOrCreate

如果给定路径上什么都不存在,自动创建空文件,权限设置为0644,属主和属组与kubelet一致

File

在给定路径上必须存在的文件,校验不通过则Pod创建失败

Socket

在给定路径上必须存在的UNIX套接字,校验不通过则Pod创建失败

CharDevice

在给定路径上必须存在的字符设备,校验不通过则Pod创建失败

BlockDevice

配置里给定路径必须是宿主机上存在的块设备文件,如/dev/sdb这类裸磁盘设备,校验不通过则Pod创建失败

3. EmptyDir与hostPath对比

关键参数

EmptyDir

hostPath

数据归属

Pod生命周期,删除Pod同时删除数据

宿主机持久保存,Pod删除数据仍然存在

初始状态

Pod启动自动创建空白目录

复用宿主机已有的文件或目录

跨节点数据

无法跨节点,更换节点清空

无法跨节点,更换节点后无法读取原数据

安全风险

低,隔离在Pod对应的临时目录

高,可访问宿主机系统文件

适用场景

Pod内多容器共享、临时缓存

节点监控、日志采集、单机本地存储

三、EmptyDir案例配置

1. 创建EmptyDir临时卷

[Step1] 本地新建YAML清单,定义Pod资源描述模板,并挂载一个EmptyDir临时卷。

root@k8s-master:~# vim emptydir-pod.yml
​
# 写入下列内容
apiVersion: v1      # 固定配置
kind: Pod           # 资源类型
metadata:
  name: emptydir-pod
spec:
  containers:
    - image: kylin-server-10-sp3b23-x86_64-20230324:b23
      imagePullPolicy: IfNotPresent
      name: kylin
      volumeMounts:             # 存储卷挂载配置
        - mountPath: /tmp       # 容器内挂载目录
          name: tmp-volume      # Volume卷名称
      args:     # 更改容器默认启动命令,自定义运行指令
        - /bin/bash
        - -c
        - sleep 10000
  volumes:      # 定义存储卷
     # 自定义存储卷名称,与[containers.volumeMounts.name]对应
     - name: tmp-volume     
       # 卷类型为EmptyDir,如果无需限制卷的空间,此时应为 emptyDir: {}
       emptyDir:
         sizeLimit: 1Gi     # 限制临时卷的最大可用空间

[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。

root@k8s-master:~# kubectl create -f emptydir-pod.yml

[Step3] 验证:查看当前集群中的所有Pod资源。

root@k8s-master:~# kubectl get pods

[Step4] 验证:查看emptydir-pod的详细信息,可以看到EmptyDir临时卷的相关信息。

root@k8s-master:~# kubectl describe pod emptydir-pod

2. 验证节点与Pod双向文件同步

[Step1] 在k8s-master上查看Pod所在节点,可以看到该Pod被调度在k8s-worker2上。

root@k8s-master:~# kubectl get pod emptydir-pod -o wide

[Step2] 在k8s-master上拼接kubelet标准路径,拿到emptydir-pod的UID。

root@k8s-master:~# kubectl get pod emptydir-pod -o jsonpath='{.metadata.uid}'

[Step3] 登录到k8s-worker2,访问对应的EmptyDir存储位置,并在目录中创建文件。

root@k8s-worker2:~# touch /var/lib/kubelet/pods/ba4fdf18-c245-4458-b092-78b14fd72dd6/volumes/kubernetes.io~empty-dir/tmp-volume/k8s-worker2.txt
root@k8s-worker2:~# ll /var/lib/kubelet/pods/ba4fdf18-c245-4458-b092-78b14fd72dd6/volumes/kubernetes.io~empty-dir/tmp-volume/

[Step4] 登录到emptydir-pod,可以在/tmp目录下看到上述我们创建的文件。

root@k8s-master:~# kubectl exec -it emptydir-pod -- /bin/bash
[root@emptydir-pod /]# ll /tmp/

[Step5] 将k8s.worker2.txt文件删除,并重新创建一个新文件。

[root@emptydir-pod /]# rm -rf /tmp/k8s-worker2.txt
[root@emptydir-pod /]# touch /tmp/emptydir-pod.txt
[root@emptydir-pod /]# ll /tmp/

[Step6] 回到到k8s-worker2,访问对应的EmptyDir存储位置,可以看到上述创建的文件。

root@k8s-worker2:~# ll /var/lib/kubelet/pods/ba4fdf18-c245-4458-b092-78b14fd72dd6/volumes/kubernetes.io~empty-dir/tmp-volume/

3. 验证Pod可用空间上限

[Step1] 登录到emptydir-pod查看分配目录的容量,可以看到空间为Host存储空间大小,而非我们定义的1G。这是因为sizeLimit字段并非将挂载目录磁盘物理容量设置为1G,而是k8s层面的写入配额限制(cgroup限额),不会直接修改文件系统自身的总磁盘大小。

root@k8s-master:~# kubectl exec -it emptydir-pod -- /bin/bash
[root@emptydir-pod /]# df -h
[root@emptydir-pod /]# exit

[Step2] 登录到emptydir-pod,在挂载目录下创建4G文件。可以看到文件已创建,但是没有任何报错信息。原因是磁盘介质的EmptyDir的“sizeLimit”并非内核实时写入拦截阈值,仅由kubelet周期性巡检做容量校验与Pod驱逐。Linux内核不支持普通磁盘目录的实时配额锁,因此dd命令可以一次性写入超额大文件,只有等待kubelet轮询检测到空间超额后才会触发处置。

root@k8s-master:~# kubectl exec -it emptydir-pod -- /bin/bash
[root@emptydir-pod /]# dd if=/dev/zero of=/tmp/2G bs=1M count=4096

[Step3] 验证:稍微等待一段时间后查看当前集群中的所有Pod资源,可以看到emptydir-pod的状态变更为“ContainerStatusUnknown”。

root@k8s-master:~# kubectl get pods

4. Pod销毁时EmptyDir同步清空

[Step1] 在k8s-master上删除emptydir-pod。

root@k8s-master:~# kubectl delete pod emptydir-pod

[Step2] 登录k8s-worker2,可以看到文件和目录已被删除。

root@k8s-worker2:~# ll /var/lib/kubelet/pods/ba4fdf18-c245-4458-b092-78b14fd72dd6/volumes/kubernetes.io~empty-dir/tmp-volume/

四、hostPath案例配置

1. 创建hostPath主机路径卷

[Step1] 本地新建YAML清单,定义Pod资源描述模板,并挂载一个hostPath主机路径卷。

root@k8s-master:~# vim hostpath-pod.yml

# 写入下列内容
apiVersion: v1		# 固定配置
kind: Pod			# 资源类型
metadata:
  name: hostpath-pod
spec:
  containers:
    - image: kylin-server-10-sp3b23-x86_64-20230324:b23
      imagePullPolicy: IfNotPresent
      name: kylin-hostpath
      volumeMounts:					# 存储卷挂载配置
        - mountPath: /hostpath-dir	# 容器内挂载目录
          name: hostpath-volume		# Volume卷名称
      args:		# 更改容器默认启动命令,自定义运行指令
        - /bin/sh
        - -c
        - sleep 10000
  volumes:		# 定义存储卷
    # 自定义存储卷名称,与[containers.volumeMounts.name]对应
    - name: hostpath-volume
      # 卷类型:hostPath主机路径卷
      hostPath:
        path: /mnt/hostpath-volume	# 宿主机上真实目录路径
        # 类型规则:宿主机上无目录则自动创建新目录,权限0755,归属kubelet
        type: DirectoryOrCreate		

[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。

root@k8s-master:~# kubectl create -f hostpath-pod.yml

[Step3] 验证:查看当前集群中的所有Pod资源。

root@k8s-master:~# kubectl get pods

[Step4] 验证:查看emptydir-pod的详细信息,可以看到EmptyDir临时卷的相关信息。

root@k8s-master:~# kubectl describe pod hostpath-pod

2. DirectoryOrCreate自动创建目录

[Step1] 查看Pod所在节点,可以看到该Pod被调度在k8s-worker2上。

root@k8s-master:~# kubectl get pod hostpath-pod -o wide

[Step2] 根据DirectoryOrCreate属性规则,当宿主机不存在目标目录时,Kubernetes会自动创建目录。在k8s-worker2上可以看到自动创建的目录。

root@k8s-worker2:~# ll /mnt/

3. 验证节点与Pod双向文件同步

[Step1] 登录到k8s-worker2,在目录中创建文件。

root@k8s-worker2:~# touch /mnt/hostpath-volume/k8s-worker2.txt

[Step2] 登录到hostpath-pod,可以在/hostpath-dir目录下看到上述我们创建的文件。

root@k8s-master:~# kubectl exec -it hostpath-pod -- /bin/bash
[root@hostpath-pod /]# ll /hostpath-dir/

[Step3] 将k8s-worker2.txt文件删除,并重新创建一个新文件。

[root@hostpath-pod /]# rm -rf /hostpath-dir/k8s-worker2.txt
[root@hostpath-pod /]# touch /hostpath-dir/hostpath-pod.txt
[root@hostpath-pod /]# ll /hostpath-dir/

[Step4] 回到k8s-worker2,可以在/hostpath-dir看到上述创建的文件。

root@k8s-worker2:~# ll /mnt/hostpath-volume/

4. 验证同节点数据仍存在

[Step1] 删除hostpath-pod,然后重新创建Pod。

root@k8s-master:~# kubectl delete pod hostpath-pod
root@k8s-master:~# kubectl create -f hostpath-pod.yml

[Step2] 查看Pod所在节点,可以看到该Pod被调度在k8s-worker2上。

root@k8s-master:~# kubectl get pod hostpath-pod -o wide

[Step3] 登录到hostpath-pod,可以看到文件仍然存在。

root@k8s-master:~# kubectl exec -it hostpath-pod -- /bin/bash
[root@hostpath-pod /]# ll /hostpath-dir/

5. 验证跨节点数据不存在

[Step1] 删除hostpath-pod,修改YAML文件指定Pod调度到k8s-worker1节点。

root@k8s-master:~# kubectl delete pod hostpath-pod

# 在spec字段下添加nodeName字段
spec:
  nodeName: k8s-worker1

[Step2] 登录到k8s-worker2,宿主机目录数据仍然存在。

root@k8s-worker2:~# ll /mnt/hostpath-volume/

[Step3] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。查看Pod所在节点,可以看到该Pod被调度在k8s-worker2上。

root@k8s-master:~# kubectl create -f hostpath-pod.yml
root@k8s-master:~# kubectl get pod hostpath-pod -o wide

[Step4] 登录到hostpath-pod,可以看到目录为空。

root@k8s-master:~# kubectl exec -it hostpath-pod -- /bin/bash
[root@hostpath-pod /]# ll /hostpath-dir/

[Step5] 登录到k8s-worker1,宿主机目录同样为空。

root@k8s-worker1:~# ll /mnt/hostpath-volume/

Kubernetes Pod健康检测、探针配置与优雅关闭 2026-10-27
Kubernetes 存储管理:PV/PVC与StorageClass 2026-10-27

评论区