从云原生走向 AI 原生:一套面向未来的架构方法论 → 阅读《AI 原生基础设施》

临时卷:emptyDir、通用临时卷、CSI 临时卷与本地临时存储配额

不是所有数据都值得持久化——缓存、临时解压、中间产物只需要"跟着 Pod 一起消失",选对临时卷类型能省下大量存储成本与运维负担。

持久卷解决的是"数据比 Pod 活得久"的问题,而大量应用只需要在 Pod 运行期间可用的暂存空间:解压的包、编译缓存、分片排序的中间文件、推理服务的模型缓存、训练任务的本地检查点。Kubernetes 把这类随 Pod 创建与删除的卷统称为临时卷(Ephemeral Volume)。本文介绍各类临时卷的特性、取舍,以及约束它们磁盘用量的 ephemeral-storage 资源模型。

临时卷的类型

类型存储位置大小约束典型用途状态
emptyDir节点根盘(kubelet 目录)或内存 tmpfssizeLimit,超出触发驱逐暂存、容器间共享、内存盘GA
configMap / secret / downwardAPI / projected节点 tmpfs由对象大小决定(≤ 1 MiB)注入配置与身份,见 投射卷GA
image容器运行时镜像存储镜像大小以只读方式挂载 OCI 镜像/工件(模型、数据集),见 镜像卷GA(v1.36)
通用临时卷(ephemeral)任意 CSI/动态供应存储PVC 请求的容量,由存储后端强制需要固定大小、网络存储或从快照初始化的暂存GA(v1.23)
CSI 临时卷(csi 内联)由 CSI 驱动在节点本地管理驱动决定Secrets Store、cert-manager csi-driver 等节点侧注入GA(v1.25)
表 1: Kubernetes 临时卷类型

emptyDir

emptyDir 在 Pod 被调度到节点时创建为空目录,Pod 中所有容器可挂载同一个 emptyDir 共享数据(这是 Sidecar 与主容器交换文件的标准方式),容器崩溃重启不丢数据,Pod 删除后随之清除。

volumes:
- name: scratch
  emptyDir:
    sizeLimit: 2Gi              # 超过即触发 Pod 驱逐(需 kubelet 开启本地临时存储隔离,默认开启)
- name: cache
  emptyDir:
    medium: Memory              # tmpfs,读写极快;用量计入容器内存 limit
    sizeLimit: 512Mi

磁盘介质的 emptyDir 存放在节点的 kubelet 根目录下(默认 /var/lib/kubelet/pods/<uid>/volumes/kubernetes.io~empty-dir/),与容器可写层、日志共用根盘。medium: Memory 则挂载 tmpfs,其容量取节点可分配内存、Pod 内存 limit 总和与 sizeLimit 三者中的最小值(SizeMemoryBackedVolumes,v1.32 GA)。内存盘的用量计入容器的内存 cgroup,写满会导致 OOM 而不是磁盘满,使用时应把它纳入内存 limits 的预算。v1.37 Alpha 的 InPlacePodVerticalScalingMemoryBackedVolumes 使 原地调整 内存 limit 后 tmpfs 大小也随之更新。

通用临时卷

emptyDir 的容量受限于节点根盘,也无法从快照初始化。通用临时卷(Generic Ephemeral Volume)让 Pod 以内联方式声明一个 PVC 模板,控制器在 Pod 创建时自动生成 PVC、按 StorageClass 动态供应卷并在 Pod 删除时一并回收:

apiVersion: v1
kind: Pod
metadata:
  name: trainer
spec:
  containers:
  - name: train
    image: registry.example.com/trainer:1.0
    volumeMounts:
    - name: ckpt
      mountPath: /checkpoints
  volumes:
  - name: ckpt
    ephemeral:
      volumeClaimTemplate:
        metadata:
          labels:
            app: trainer
        spec:
          accessModes: ["ReadWriteOnce"]
          storageClassName: fast-nvme          # 任意支持动态供应的 StorageClass
          resources:
            requests:
              storage: 200Gi
          # dataSource:                        # 可从快照或已有 PVC 初始化
          #   kind: VolumeSnapshot
          #   name: dataset-v3
          #   apiGroup: snapshot.storage.k8s.io

自动创建的 PVC 名称为 <Pod 名>-<卷名>(此例为 trainer-ckpt),ownerReference 指向 Pod,因此 Pod 删除时 PVC 被垃圾回收,PV 按 StorageClass 的 reclaimPolicy 处理。命名的确定性也带来一个注意点:若命名空间中已存在同名 PVC 且不属于该 Pod,Pod 会一直处于 Pending 并报告冲突,避免误用他人的卷。

通用临时卷与 StatefulSet 的 volumeClaimTemplates 形似但语义相反:后者的 PVC 在 Pod 删除后保留,用于有状态副本;前者的 PVC 与 Pod 同生共死。它适合这些场景:

  • 需要比节点根盘更大或性能更可控的暂存空间(本地 NVMe StorageClass、云块存储)
  • 从数据集快照快速克隆一份可写副本供单次任务使用
  • 希望暂存用量由存储后端硬性限制而非依赖驱逐
  • 使用 WaitForFirstConsumer 绑定模式时,卷与 Pod 自然同区

由于通用临时卷会真实创建 PVC,它受 ResourceQuota 中 persistentvolumeclaims 与 requests.storage 的约束,且创建 Pod 的用户必须有权创建 PVC——这一点由 API Server 在准入阶段隐式检查。

CSI 临时卷

CSI 临时卷(CSI Ephemeral / Inline Volume)由支持 Ephemeral 生命周期模式的 CSI 驱动直接在节点上创建,不经过 PVC/PV 对象,概念上更接近 secret/configMap。它主要用于把外部系统的数据以文件形式注入 Pod:

volumes:
- name: secrets-store
  csi:
    driver: secrets-store.csi.k8s.io
    readOnly: true
    volumeAttributes:
      secretProviderClass: vault-db-creds     # 由驱动解释的参数

常见实现包括 Secrets Store CSI Driver(从 Vault、云 Secrets Manager 挂载密钥)、cert-manager 的 csi-driver(为 Pod 签发证书,与 podCertificate 投射卷目标相近)以及部分本地存储驱动。驱动必须在其 CSIDriver 对象的 volumeLifecycleModes 中声明 Ephemeral;由于 volumeAttributes 由 Pod 作者任意填写并直接传给特权的驱动进程,Pod 安全标准只在 baseline/restricted 级别允许 csi 卷类型本身,集群管理员应通过 CSIDriver 的 volumeLifecycleModes 与准入策略限制哪些驱动可以内联使用。

本地临时存储资源

emptyDir(磁盘介质)、容器可写层与容器日志共同消耗节点的本地临时存储(ephemeral-storage),Kubernetes 把它作为一种可请求、可限制的资源:

containers:
- name: app
  resources:
    requests:
      ephemeral-storage: "2Gi"
    limits:
      ephemeral-storage: "8Gi"

调度器按 requests.ephemeral-storage 的总和与节点 Allocatable 匹配;kubelet 定期(默认 10 秒)统计每个容器的可写层与日志、每个 Pod 的 emptyDir 用量,容器超过 limit 或 Pod 中所有容器 limit 之和被超过时驱逐 Pod(emptyDir 的 sizeLimit 同理)。由于统计是周期性扫描,短时间内的突发写入可能超过限制后才被发现;开启 LocalStorageCapacityIsolationFSQuotaMonitoring(v1.31 起 Beta,默认关闭)可改用 XFS/ext4 项目配额做精确、实时的用量统计。

节点级的磁盘保护则由 节点压力驱逐 的 nodefs.available/imagefs.available 阈值兜底;若节点为镜像与容器可写层配置了独立磁盘(KubeletSeparateDiskGC),emptyDir 与日志仍在 nodefs 上统计。命名空间级的总量可通过 ResourceQuota 的 requests.ephemeral-storage/limits.ephemeral-storage 限制,LimitRange 可为未声明的容器设置默认值。

选型建议

需求推荐
几百 MB 以内的暂存、容器间共享文件emptyDir + sizeLimit + ephemeral-storage limit
低延迟缓存、不希望落盘emptyDir 的 medium: Memory,纳入内存预算
数十 GB 以上暂存、训练检查点、需要本地 NVMe通用临时卷 + 本地或块存储 StorageClass
从数据集快照克隆可写副本通用临时卷 + dataSource
只读模型/数据集分发image 卷
注入外部密钥、证书CSI 临时卷(Secrets Store、cert-manager)或 projected 卷
表 2: 临时存储选型

总结

临时卷覆盖了"数据不需要比 Pod 活得久"的全部场景:emptyDir 简单直接但受节点根盘约束,内存介质提供极致性能却占用内存预算,通用临时卷把动态供应与快照能力带入暂存空间并随 Pod 自动回收,CSI 临时卷与投射卷负责注入外部数据。无论选择哪一种,都应为容器声明 ephemeral-storage 的 requests/limits 并为 emptyDir 设置 sizeLimit,让暂存用量成为可调度、可限制、可驱逐的一等资源,而不是悄悄吃光节点磁盘的隐患。

参考文献

创建于 2026/11/01 更新于 2026/11/01 2614 字 阅读约 6 分钟

提交勘误/建议