Volumes and Ephemeral Storage
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages. |
Containers are disposable: a container’s writable layer disappears when it is restarted, and a Pod’s storage vanishes when the Pod is deleted or evicted. A Kubernetes volume solves two problems at once: it survives container restarts within a Pod, and it lets containers in a Pod share files. This page covers volumes whose lifetime is bounded by the Pod — "ephemeral storage". Storage that outlives Pods is in Persistent Volumes and Storage Classes. This page is written against Kubernetes 1.37; see the section index for the version baseline.
Container filesystem versus Pod volume
Rensin’s 2015 book already draws the line that still defines the model: a container volume (Docker’s VOLUME, a
bind-mounted host path) belongs to one container and is tied to the host, whereas a Pod volume is declared once in
spec.volumes and mounted by name into any container of the Pod through volumeMounts, so containers can share it and
the orchestrator can decide where it is backed. The book’s list (EmptyDir, NFS, GCEPersistentDisk) shows both halves of
this page: emptyDir is the ephemeral one, while NFS and cloud disks are persistent storage. Two warnings have aged: the
in-tree gcePersistentDisk and similar cloud-provider volume types were removed in favour of CSI drivers, and
NFS is now normally consumed through a PersistentVolume.
Every container also has a writable layer of its own. It is slow, is lost on container restart, and counts against the node’s ephemeral storage, so data that must outlive a restart goes in a volume.
Source: Kubernetes Docs — Volumes.
emptyDir
An emptyDir is created empty when the Pod is assigned to a node and deleted with the Pod. It survives container
crashes, which makes it the standard scratch space, cache and inter-container hand-off (for example a sidecar writing
files that the main container serves).
apiVersion: v1
kind: Pod
metadata:
name: catalog-api-with-sidecar
namespace: bookshelf
spec:
containers:
- name: catalog-api
image: ghcr.io/example/bookshelf-catalog-api:1.0.0
volumeMounts:
- name: scratch
mountPath: /tmp/work
- name: shared-logs
mountPath: /var/log/catalog
- name: log-forwarder
image: ghcr.io/example/bookshelf-log-forwarder:1.0.0
volumeMounts:
- name: shared-logs
mountPath: /logs
readOnly: true
volumes:
- name: scratch
emptyDir:
sizeLimit: 500Mi
- name: shared-logs
emptyDir:
medium: Memory # tmpfs; counts against container memory limits
sizeLimit: 64Mi
Source: Kubernetes Docs — emptyDir.
-
medium: Memorybacks the volume with RAM (tmpfs): fast and never written to disk, but its usage is charged to the container memory limit (see Resource Management). -
sizeLimitbounds it; the kubelet evicts the Pod if the limit is exceeded. Without a limit on the default medium, a runaway writer fills the node’s disk. -
An
emptyDiris also how init containers pass prepared files to the main containers (Health Probes and Container Lifecycle).
hostPath and its risks
A hostPath volume mounts a file or directory of the node’s filesystem into the Pod. It is indispensable for node
agents (the log agent in DaemonSets reads /var/log/pods) and dangerous
everywhere else: the Pod’s data is bound to one node, contents differ per node, and a writable mount of a sensitive
path (the container runtime socket, /etc, kubelet directories) is a container-escape primitive. Pod Security
forbids hostPath already at the baseline level (and therefore also at restricted) (Pod Security). If it is
unavoidable, mount the narrowest path, readOnly: true, and set the type check.
volumes:
- name: pod-logs
hostPath:
path: /var/log/pods
type: Directory # fail if the path is missing or is not a directory
Source: Kubernetes Docs — hostPath. For single-node development prefer a local PersistentVolume, see Persistent Volumes and Storage Classes.
Volumes backed by API objects and projected volumes
configMap, secret and downwardAPI volumes (ConfigMaps,
Secrets) expose API data as files. A projected volume merges several of these
sources into a single directory, so an application sees one mount point:
containers:
- name: catalog-api
image: ghcr.io/example/bookshelf-catalog-api:1.0.0
volumeMounts:
- name: combined
mountPath: /etc/catalog
readOnly: true
volumes:
- name: combined
projected:
sources:
- configMap:
name: catalog-config
- secret:
name: catalog-db
items:
- key: DB_USER
path: db/user
- downwardAPI:
items:
- path: labels
fieldRef:
fieldPath: metadata.labels
- serviceAccountToken:
path: api-audience-token # short-lived, audience-bound
audience: reviews-api
expirationSeconds: 3600
Source: Kubernetes Docs — Projected Volumes.
The serviceAccountToken source is how Pods obtain short-lived, audience-scoped credentials instead of the legacy
long-lived token Secrets; see Authentication, Authorization and RBAC.
Generic and CSI ephemeral volumes
Two inline forms give a Pod its own provisioned volume that is created and deleted with it:
-
Generic ephemeral volume (
ephemeral.volumeClaimTemplate): the Pod controller creates a PersistentVolumeClaim owned by the Pod, so any StorageClass can provide per-Pod scratch space larger or faster thanemptyDir, with capacity tracking, snapshots and resizing. -
CSI ephemeral volume (
csiinline): a CSI driver that supportsEphemeralmode creates the volume at Pod start from inline attributes; used by drivers such as the Secrets Store CSI driver.
volumes:
- name: scratch-fast
ephemeral:
volumeClaimTemplate:
metadata:
labels:
app: catalog-api
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 2Gi
Source: Kubernetes Docs — Ephemeral Volumes.
Image volumes
An image volume mounts the content of an OCI image or artifact, read-only, directly as a volume. It separates data from the application image: ship model files, static assets or configuration bundles as their own versioned artifacts from a registry, without baking them into the application image or copying them with an init container. The feature graduated to stable in 1.36; verify against the docs for your cluster version and container runtime, as runtime support is required.
containers:
- name: web
image: ghcr.io/example/bookshelf-web:1.0.0
volumeMounts:
- name: static-assets
mountPath: /usr/share/assets
volumes:
- name: static-assets
image:
reference: ghcr.io/example/bookshelf-assets:2026.09
pullPolicy: IfNotPresent
subPath, readOnly and mount propagation
-
subPathmounts a single file or subdirectory of a volume instead of its root, so several containers (or several mounts) can use different parts of one volume. Remember thatsubPathmounts of ConfigMap and Secret volumes do not receive updates.subPathExprbuilds the path from environment variables such as the Pod name. -
readOnly: trueon avolumeMountmakes the mount read-only for that container; use it everywhere a container does not need to write.recursiveReadOnly: Enabledalso makes submounts read-only. -
mountPropagationcontrols whether mounts made inside a container become visible on the host or in other containers.Noneis the default;HostToContainerlets a node agent see mounts the host adds later;Bidirectionalalso propagates container mounts to the host and requires a privileged container, so it is reserved for storage drivers.
Source: Kubernetes Docs — Using subPath and Mount propagation.
Local ephemeral storage requests and limits
Container writable layers, logs and emptyDir volumes on the default medium all consume the node’s local ephemeral
storage. It is a resource like CPU and memory: ephemeral-storage can be requested (used by the scheduler) and
limited (enforced by the kubelet, which evicts a Pod that exceeds it).
resources:
requests:
ephemeral-storage: 1Gi
limits:
ephemeral-storage: 2Gi
Combined with sizeLimit on emptyDir, this keeps a misbehaving Pod from exhausting the node’s disk; quotas and
LimitRanges extend the same limits per namespace (Resource Management).