Compare the Kubernetes volume types emptyDir, hostPath, and generic ephemeral volumes (the ephemeral.volumeClaimTemplate field in a Pod spec). What is each for, and why is hostPath discouraged in multi-tenant clusters?
answer
- emptyDir = kubelet scratch, Pod lifetime
- hostPath = node filesystem, security + node pinning
- runtime socket mount = node root
- ephemeral.volumeClaimTemplate = PVC owned by Pod
- local PV, not hostPath, for node-local persistence
basics
~20 semptyDir is per-Pod scratch space managed by kubelet. hostPath mounts an arbitrary node directory into the container, which pins the Pod to that node and can expose the host, so it is restricted. Generic ephemeral volumes create a real provisioned claim that is deleted with the Pod.
solid answer
~50 s**emptyDir** — a directory kubelet creates on the node for one Pod and deletes with it. Optional `medium: Memory` (tmpfs) and `sizeLimit`. Best for scratch and init-container-to-main handoff. **hostPath** — mounts a path from the node's own filesystem. Two problems: it silently couples the Pod to one node's contents (nothing recreates that path elsewhere), and it is a privilege-escalation vector — mounting `/`, `/var/run/*.sock`, kubelet's directory or writable host binaries can lead to node takeover. The Pod Security Standards' Baseline and Restricted profiles forbid it. Legitimate uses are node agents: log shippers, CNI plugins, node exporters. **Generic ephemeral volumes** — declared inline in the Pod as `ephemeral.volumeClaimTemplate`; Kubernetes creates a real PVC owned by the Pod, provisions it through a StorageClass, and deletes it when the Pod goes away. You get size, class, and block-mode support with Pod-scoped lifetime — the modern replacement for "emptyDir but bigger/faster".
code
yaml · 21 linesvolumes:
- name: scratch
emptyDir:
sizeLimit: 2Gi
- name: hostlogs # node-agent use only
hostPath:
path: /var/log
type: Directory
- name: bigcache
ephemeral:
volumeClaimTemplate:
metadata:
labels: { purpose: build-cache }
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 200Gigo deeper
Know emptyDir is scratch, hostPath touches the node and is discouraged, and that neither survives the Pod.
Give concrete hostPath dangers and node-pinning behavior, and describe generic ephemeral volumes as a Pod-owned PVC.
Discuss policy enforcement (Pod Security Standards, admission policy), local PVs as the supported node-local alternative, and node disk-pressure blast radius from unbounded emptyDir.
Position these as tenancy boundaries: which volume types a shared platform permits, what the allowlist for node agents looks like, and how scratch capacity is budgeted per node.
## Three ways to get non-persistent storage All three types appear under `spec.volumes` and none of them is meant to outlive the Pod. They differ in *where the bytes live* and *who controls them*. ### emptyDir Kubelet creates a directory under its own data root on the node when the Pod is bound there, mounts it into the requesting containers, and deletes it when the Pod is removed. Key properties: - Survives container restarts inside the Pod; does not survive rescheduling. - `medium: Memory` makes it a tmpfs: RAM-backed, very fast, cleared on Pod removal, and — importantly — the bytes count toward the Pod's memory usage and can trigger an OOM kill. - `sizeLimit` bounds usage; exceeding it makes the Pod eligible for eviction. Without it, one Pod filling the node's disk causes `DiskPressure`, image garbage collection, and evictions of unrelated Pods. Ephemeral-storage requests/limits on containers are the companion control. - Contents are only visible to containers in that Pod, which is exactly why it is the idiomatic init-container handoff. ### hostPath This mounts an existing (or, with some types, newly created) path from the node's filesystem straight into the container. It is the sharpest tool in the box: - **Security.** A Pod that can mount `/` reads every secret on the node. Mounting the container runtime socket (`/var/run/containerd/containerd.sock`) is effectively root on the node, because you can start a privileged container. Mounting kubelet's directory exposes every projected ServiceAccount token on that node. Mounting a writable host binary or unit directory allows persistence. For these reasons the Pod Security Standards forbid hostPath in Baseline and Restricted, and policy engines usually block it outright or allow only an explicit path allowlist. - **Correctness.** The data is node-local and nothing replicates or recreates it. Reschedule the Pod and it sees a different node's filesystem — usually an empty or nonexistent path. `type: DirectoryOrCreate` then silently creates an empty directory, which turns a storage bug into a data-loss-looking bug. - **Ownership and SELinux/permissions** are the node's, not Kubernetes', so files often appear root-owned and unreadable by a non-root container. Legitimate uses are all *node-agent* shaped, run as DaemonSets by cluster operators: log collectors reading `/var/log`, metrics exporters reading `/proc` and `/sys`, CNI/CSI plugins writing to their plugin directories. If your application is not an agent for the node itself, hostPath is the wrong answer — and for node-local *persistent* storage, the supported mechanism is a `local` PersistentVolume with node affinity, which at least makes the node pinning explicit to the scheduler. ### Generic ephemeral volumes Declared inline in the Pod: ``` volumes: - name: scratch ephemeral: volumeClaimTemplate: spec: accessModes: ["ReadWriteOnce"] storageClassName: fast-ssd resources: { requests: { storage: 200Gi } } ``` Kubernetes creates a PVC named `<pod>-<volume>` owned by the Pod. It is provisioned by a normal StorageClass through the normal dynamic-provisioning path, and when the Pod is deleted the owner reference garbage-collects the PVC, which — with the usual `Delete` reclaim policy — destroys the volume. Why it exists: emptyDir can only give you node disk, with no class, no IOPS guarantee, no block mode, and no isolation from other Pods' writes. Generic ephemeral volumes give you everything dynamic provisioning offers with Pod-scoped lifetime. They are the right choice for large build caches, scratch space for data processing, or anything needing a specific performance tier temporarily. A related, narrower type is the **CSI ephemeral volume** (`csi:` inline in the Pod), used by drivers that inject data rather than provide capacity — secrets-store drivers being the common example. That path does not create a PVC at all. ## Choosing quickly - Small scratch, no special requirements → **emptyDir** with a `sizeLimit`. - Need real capacity, a storage class, or block mode, but only for the Pod's life → **generic ephemeral volume**. - Need to read or write the node itself, and you are writing a node agent → **hostPath**, narrowly scoped, read-only where possible. - Need data to survive the Pod → none of these; use a PersistentVolumeClaim.
- Why does mounting the container runtime socket with hostPath amount to giving away the node?The socket is the runtime's control API, and anything that can talk to it can create containers with arbitrary options — privileged, host PID and network namespaces, the host root filesystem bind-mounted in. From there an attacker reads every secret and credential on the node and can run code as root outside any container boundary. That is why Baseline and Restricted Pod Security Standards reject hostPath outright.
- When would you pick a generic ephemeral volume over an emptyDir?When you need properties emptyDir cannot express: a specific StorageClass and performance tier, capacity beyond what node disk can safely give, raw block mode, or isolation from other Pods sharing the node's disk. The lifetime is the same — the claim is owned by the Pod and garbage-collected with it — so you gain capability without gaining durability.
saying these in an interview costs you the question
- Recommending hostPath as the way to get persistent storage
- Assuming hostPath data follows the Pod when it reschedules
- Forgetting that emptyDir with medium: Memory consumes the Pod's memory budget
- Thinking generic ephemeral volumes survive the Pod
- Leaving emptyDir unbounded and blaming the node for DiskPressure evictions