| Tested on | Rocky Linux 10.2 (Red Quartz) workstation |
|---|---|
| Package | kubectl 1.36.3 |
| Applies to | Any host with kubectl configured; Kubernetes cluster with Linux worker nodes |
| Cert prep | CKA · CKAD |
| Lab environment | Multi-node kubeadm cluster with containerd — install Kubernetes with kubeadm |
| Privilege | Normal user (no sudo required on the workstation) |
| Scope | subPath and mountPath, why to use subPath, multiple mounts from one volume, ConfigMap and Secret file mounts, directory preservation, ConfigMap update limitations, file and directory rules, permission troubleshooting, subPathExpr, and when to use subPath. Does not cover PV administration, StorageClasses, full ConfigMap or Secret tutorials, Downward API depth, or CSI drivers. |
This walkthrough uses the subpath-lab namespace. You will mount one subdirectory from a shared volume, replace only nginx.conf while keeping other files under /etc/nginx, and prove that a ConfigMap mounted with subPath does not update until you recreate the Pod.
What Is subPath in Kubernetes?
volumeMounts.mountPathdefines where a volume appears inside the containersubPathselects a specific file or directory inside that volume instead of mounting the volume root- Without
subPath, Kubernetes mounts the volume atmountPathand hides image files at that path - With
subPath, only the chosen file or directory appears atmountPath subPathis set on eachcontainers[].volumeMountsentry
Pod-level volumes and volumeMounts basics are covered in Kubernetes volumes.
mountPath vs subPath
| Field | Purpose |
|---|---|
name |
References the Pod-level volume |
mountPath |
Destination inside the container |
subPath |
File or directory selected from the volume |
Example mounting only the website directory from a volume at /usr/share/nginx/html:
volumeMounts:
- name: application-data
mountPath: /usr/share/nginx/html
subPath: websiteOnly the website subtree from the volume appears at /usr/share/nginx/html. Other paths on the volume are not visible at that mount point.
Why Use subPath?
A normal volumeMount replaces everything at mountPath. subPath solves common cases where you need a narrower mount:
- Mount one configuration file at a fixed path the application expects, such as
/etc/nginx/nginx.conf - Keep other files from the container image in the same directory, such as
mime.typesandconf.d - Mount different subdirectories from one shared volume at different container paths
- Give each Pod its own subdirectory with
subPathExprwhen the path comes from metadata or environment variables
The trade-off is update behaviour. ConfigMap and Secret files mounted through subPath do not receive live projected-file updates. The labs below show that limitation and the mount rules to follow.
Mount Different Directories from One Volume
- One volume can supply multiple mount points when each
volumeMountsentry uses a differentsubPath - An init container prepares the source layout before the application container starts
An init container prepares this layout on an emptyDir volume:
data/
├── html/
└── logs/Save multi-subpath.yaml:
apiVersion: v1
kind: Pod
metadata:
name: multi-subpath
namespace: subpath-lab
spec:
initContainers:
- name: setup
image: busybox:1.36
command: ["sh", "-c", "mkdir -p /data/html /data/logs && echo page > /data/html/index.html && echo ok > /data/logs/access.log"]
volumeMounts:
- name: data
mountPath: /data
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo html:$(cat /var/www/html/index.html) logs:$(cat /var/log/app/access.log) && sleep 3600"]
volumeMounts:
- name: data
mountPath: /var/www/html
subPath: html
- name: data
mountPath: /var/log/app
subPath: logs
volumes:
- name: data
emptyDir: {}Create the namespace and apply the Pod:
kubectl create namespace subpath-labkubectl apply -f multi-subpath.yamlkubectl wait --for=condition=Ready pod/multi-subpath -n subpath-lab --timeout=90skubectl logs multi-subpath -n subpath-labSample output:
html:page logs:okBoth mounts reference volume name data with different subPath values.
Mount Individual ConfigMap and Secret Files
Use subPath when the application reads one file at a fixed path instead of a whole mounted directory.
Replace only nginx.conf
Create a ConfigMap with a minimal nginx.conf:
kubectl create configmap nginx-conf -n subpath-lab --from-file=nginx.conf=/dev/stdin <<'EOF'
worker_processes 2;
events { worker_connections 1024; }
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server { listen 80; location / { return 200 'ok'; } }
}
EOFSave nginx-subpath.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx-subpath
namespace: subpath-lab
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
readOnly: true
volumes:
- name: nginx-config
configMap:
name: nginx-confkubectl apply -f nginx-subpath.yamlkubectl wait --for=condition=Ready pod/nginx-subpath -n subpath-lab --timeout=90sRead the mounted file:
kubectl exec nginx-subpath -n subpath-lab -- head -1 /etc/nginx/nginx.confSample output:
worker_processes 2;For a ConfigMap or Secret volume:
- Without
items, each key normally becomes a file with the same name, sosubPathuses that filename - When
items[].pathremaps a key,subPathmust reference the projected path inside the volume—not the original key
ConfigMap creation and env-var usage are covered in Kubernetes ConfigMaps.
Preserve files from the container image
Without subPath:
- Mounting a whole ConfigMap volume at
/etc/nginxhidesmime.types,conf.d, and other image files at that path
With subPath:
- Only
nginx.confis replaced - Other files under
/etc/nginxremain from the image
List other files still present under /etc/nginx:
kubectl exec nginx-subpath -n subpath-lab -- ls /etc/nginxSample output:
conf.d
fastcgi.conf
fastcgi_params
mime.types
modules
nginx.conf
scgi_params
uwsgi_paramsmime.types and conf.d remain from the image beside the mounted nginx.conf.
Mount one Secret key
- Mount one Secret key as one file with a read-only mount
- The destination filename can differ from the Secret key name
volumeMounts:
- name: creds
mountPath: /etc/creds/db-password
subPath: password
readOnly: true
volumes:
- name: creds
secret:
secretName: db-credThe destination filename db-password can differ from the Secret key password. Secret creation and rotation belong in Kubernetes Secrets.
Understand ConfigMap and Secret Update Limitations
- A ConfigMap or Secret mounted as a normal directory volume can receive eventual projected-file updates
- The application must reread the file to observe the new content
- A
subPathfile mount remains bound to the original projected file and does not receive those updates - Recreate a bare Pod, or update and roll out the Pod template of its Deployment, StatefulSet, or other controller
- Updating the ConfigMap or Secret alone does not refresh an existing
subPathmount mountPath,subPath, andsubPathExprare part of the container's volume-mount configuration and cannot be changed on an existing Pod- Changing them also requires Pod replacement
- Container
volumeMountsare immutable on an existing Pod
Create a ConfigMap and Pod that mount one file with subPath:
kubectl create configmap app-conf -n subpath-lab --from-literal=app.properties="version=1"Save cm-subpath.yaml:
apiVersion: v1
kind: Pod
metadata:
name: cm-subpath
namespace: subpath-lab
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "cat /etc/app.properties && sleep 3600"]
volumeMounts:
- name: cfg
mountPath: /etc/app.properties
subPath: app.properties
readOnly: true
volumes:
- name: cfg
configMap:
name: app-confkubectl apply -f cm-subpath.yamlkubectl wait --for=condition=Ready pod/cm-subpath -n subpath-lab --timeout=60sRead the file before the update:
kubectl exec cm-subpath -n subpath-lab -- cat /etc/app.propertiesSample output:
version=1Change the ConfigMap data:
kubectl create configmap app-conf -n subpath-lab --from-literal=app.properties="version=2" -o yaml --dry-run=client | kubectl apply -f -Read the same file in the running Pod:
kubectl exec cm-subpath -n subpath-lab -- cat /etc/app.propertiesSample output:
version=1The mounted file still shows version=1 even though the ConfigMap object changed. Delete and recreate the Pod:
kubectl delete pod cm-subpath -n subpath-lab --wait=truekubectl apply -f cm-subpath.yamlkubectl wait --for=condition=Ready pod/cm-subpath -n subpath-lab --timeout=60skubectl exec cm-subpath -n subpath-lab -- cat /etc/app.propertiesSample output:
version=2Plan for Pod recreation or rollout when you mount ConfigMap or Secret keys through subPath.
Follow File and Directory Mount Rules
subPathis relative to the referenced volume root; do not use an absolute path- It must not contain path traversal such as
.. - The selected source must have the correct type: file-to-file or directory-to-directory
- Ensure the selected file or directory exists before the application container starts
- For a file mount, the destination
mountPathincludes the destination filename - The destination parent directory must exist in the container filesystem
- When ConfigMap or Secret
itemsis configured, use the projected path assubPath - Kubernetes treats
subPathas a relative path inside the volume and rejects absolute or relative traversal components - Source directories and files must exist before mounting them
For example, when items remaps a key:
volumes:
- name: nginx-config
configMap:
name: nginx-conf
items:
- key: nginx.conf
path: custom/nginx.confThe corresponding mount would use:
subPath: custom/nginx.confConfigMap keys become filenames unless items maps them to different relative paths.
Use subPathExpr for Dynamic Subdirectories
subPathis a literal pathsubPathExprexpands$(VAR_NAME)from the container environment- The two fields are mutually exclusive
- This example uses the Downward API to set
POD_NAME - An init container creates the selected directory before the application starts
Save this manifest as expr-demo.yaml:
apiVersion: v1
kind: Pod
metadata:
name: expr-demo
namespace: subpath-lab
spec:
initContainers:
- name: prepare
image: busybox:1.36
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- sh
- -c
- mkdir -p "/data/${POD_NAME}"
volumeMounts:
- name: data
mountPath: /data
containers:
- name: app
image: busybox:1.36
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- sh
- -c
- echo hello > /logs/hello.txt && sleep 3600
volumeMounts:
- name: data
mountPath: /logs
subPathExpr: $(POD_NAME)
volumes:
- name: data
emptyDir: {}kubectl apply -f expr-demo.yamlkubectl wait --for=condition=Ready pod/expr-demo -n subpath-lab --timeout=90skubectl exec expr-demo -n subpath-lab -- cat /logs/hello.txtSample output:
helloField and environment expansion details live in container command, args, and environment.
Troubleshoot Common subPath Problems
| Symptom | Likely cause | First check |
|---|---|---|
permission denied |
Source mode, ownership, container user, or parent-directory permissions | ls -l and container security context |
not a directory |
File source mounted on directory target, or the reverse | Source and destination types |
no such file or directory |
Wrong subPath, missing key/path, or missing target parent |
Volume contents and items[].path |
Pod stuck in ContainerCreating |
Kubelet could not prepare the mount | kubectl describe pod Events |
| ConfigMap change is not visible | File is mounted through subPath |
Recreate or roll out the Pod |
Inspect Events for mount failures:
kubectl describe pod nginx-subpath -n subpath-labLook for messages about invalid paths, missing sources, or file versus directory mismatches in the Events section.
When Should You Use subPath?
After the labs above, use this checklist:
Use subPath when:
- You need one configuration file at a fixed path
- You must preserve other files in the destination directory from the image
- One volume should supply different subdirectories at different
mountPathvalues - Multiple containers in one Pod need different portions of the same volume
- The subdirectory name should come from metadata or environment variables through
subPathExpr
Avoid subPath when:
- The application needs live ConfigMap or Secret file updates without restarting
- Mounting the full volume at a dedicated directory is safe
- The application can read configuration from a separate mounted directory
What's Next
- Fix Pending PVC, FailedMount and Volume Attachment Errors
- Kubernetes Networking Model, CNI and kube-proxy
- Kubernetes Services, Endpoints and EndpointSlices
References
Summary
subPathmounts one file or subdirectory from a Pod volume instead of replacing everything atmountPath- The labs split one
emptyDiracross/var/www/htmland/var/log/app, and replaced onlynginx.confwhilemime.typesandconf.dstayed on disk from the image - ConfigMap and Secret files mounted through
subPathdo not refresh when the source object changes - The update lab showed
version=1persisting after the ConfigMap moved toversion=2until the Pod was recreated - Use directory mounts or application reload patterns when you need live config without restart

