Kubernetes subPath Volume Mounts with Examples

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.mountPath defines where a volume appears inside the container
  • subPath selects a specific file or directory inside that volume instead of mounting the volume root
  • Without subPath, Kubernetes mounts the volume at mountPath and hides image files at that path
  • With subPath, only the chosen file or directory appears at mountPath
  • subPath is set on each containers[].volumeMounts entry

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:

yaml
volumeMounts:
  - name: application-data
    mountPath: /usr/share/nginx/html
    subPath: website

Only 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.types and conf.d
  • Mount different subdirectories from one shared volume at different container paths
  • Give each Pod its own subdirectory with subPathExpr when 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 volumeMounts entry uses a different subPath
  • An init container prepares the source layout before the application container starts

An init container prepares this layout on an emptyDir volume:

text
data/
├── html/
└── logs/

Save multi-subpath.yaml:

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:

bash
kubectl create namespace subpath-lab
bash
kubectl apply -f multi-subpath.yaml
bash
kubectl wait --for=condition=Ready pod/multi-subpath -n subpath-lab --timeout=90s
bash
kubectl logs multi-subpath -n subpath-lab

Sample output:

output
html:page logs:ok

Both 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:

bash
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'; } }
}
EOF

Save nginx-subpath.yaml:

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-conf
bash
kubectl apply -f nginx-subpath.yaml
bash
kubectl wait --for=condition=Ready pod/nginx-subpath -n subpath-lab --timeout=90s

Read the mounted file:

bash
kubectl exec nginx-subpath -n subpath-lab -- head -1 /etc/nginx/nginx.conf

Sample output:

output
worker_processes 2;

For a ConfigMap or Secret volume:

  • Without items, each key normally becomes a file with the same name, so subPath uses that filename
  • When items[].path remaps a key, subPath must 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/nginx hides mime.types, conf.d, and other image files at that path

With subPath:

  • Only nginx.conf is replaced
  • Other files under /etc/nginx remain from the image

List other files still present under /etc/nginx:

bash
kubectl exec nginx-subpath -n subpath-lab -- ls /etc/nginx

Sample output:

output
conf.d
fastcgi.conf
fastcgi_params
mime.types
modules
nginx.conf
scgi_params
uwsgi_params

mime.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
yaml
volumeMounts:
  - name: creds
    mountPath: /etc/creds/db-password
    subPath: password
    readOnly: true
volumes:
  - name: creds
    secret:
      secretName: db-cred

The 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 subPath file 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 subPath mount
  • mountPath, subPath, and subPathExpr are part of the container's volume-mount configuration and cannot be changed on an existing Pod
  • Changing them also requires Pod replacement
  • Container volumeMounts are immutable on an existing Pod

Create a ConfigMap and Pod that mount one file with subPath:

bash
kubectl create configmap app-conf -n subpath-lab --from-literal=app.properties="version=1"

Save cm-subpath.yaml:

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-conf
bash
kubectl apply -f cm-subpath.yaml
bash
kubectl wait --for=condition=Ready pod/cm-subpath -n subpath-lab --timeout=60s

Read the file before the update:

bash
kubectl exec cm-subpath -n subpath-lab -- cat /etc/app.properties

Sample output:

output
version=1

Change the ConfigMap data:

bash
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:

bash
kubectl exec cm-subpath -n subpath-lab -- cat /etc/app.properties

Sample output:

output
version=1

The mounted file still shows version=1 even though the ConfigMap object changed. Delete and recreate the Pod:

bash
kubectl delete pod cm-subpath -n subpath-lab --wait=true
bash
kubectl apply -f cm-subpath.yaml
bash
kubectl wait --for=condition=Ready pod/cm-subpath -n subpath-lab --timeout=60s
bash
kubectl exec cm-subpath -n subpath-lab -- cat /etc/app.properties

Sample output:

output
version=2

Plan for Pod recreation or rollout when you mount ConfigMap or Secret keys through subPath.


Follow File and Directory Mount Rules

  • subPath is 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 mountPath includes the destination filename
  • The destination parent directory must exist in the container filesystem
  • When ConfigMap or Secret items is configured, use the projected path as subPath
  • Kubernetes treats subPath as 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:

yaml
volumes:
  - name: nginx-config
    configMap:
      name: nginx-conf
      items:
        - key: nginx.conf
          path: custom/nginx.conf

The corresponding mount would use:

yaml
subPath: custom/nginx.conf

ConfigMap keys become filenames unless items maps them to different relative paths.

Use subPathExpr for Dynamic Subdirectories

  • subPath is a literal path
  • subPathExpr expands $(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:

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: {}
bash
kubectl apply -f expr-demo.yaml
bash
kubectl wait --for=condition=Ready pod/expr-demo -n subpath-lab --timeout=90s
bash
kubectl exec expr-demo -n subpath-lab -- cat /logs/hello.txt

Sample output:

output
hello

Field 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:

bash
kubectl describe pod nginx-subpath -n subpath-lab

Look 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 mountPath values
  • 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


References


Summary

  • subPath mounts one file or subdirectory from a Pod volume instead of replacing everything at mountPath
  • The labs split one emptyDir across /var/www/html and /var/log/app, and replaced only nginx.conf while mime.types and conf.d stayed on disk from the image
  • ConfigMap and Secret files mounted through subPath do not refresh when the source object changes
  • The update lab showed version=1 persisting after the ConfigMap moved to version=2 until the Pod was recreated
  • Use directory mounts or application reload patterns when you need live config without restart

Frequently Asked Questions

1. What is the difference between mountPath and subPath?

mountPath is where the volume appears inside the container. subPath selects one file or directory inside that volume instead of mounting the volume root. Without subPath, the mount replaces the directory view at mountPath.

2. Why do my image files disappear after I add a volumeMount?

Mounting a volume at mountPath hides files from the image at that path. Use subPath to mount one file or subdirectory while leaving other files in the parent directory visible.

3. Does a ConfigMap mounted with subPath update automatically?

No. ConfigMap and Secret files mounted through subPath do not receive live updates when the source object changes. Recreate a bare Pod, or update and roll out the Pod template of its Deployment, StatefulSet, or other controller.

4. Can I mount different parts of one volume in the same Pod?

Yes. Add multiple volumeMounts entries that reference the same volume name with different subPath and mountPath values.

5. When should I avoid subPath?

Avoid subPath when the application needs automatic ConfigMap or Secret file refresh without restarting the Pod, or when mounting the whole volume at a dedicated directory is safe and simpler.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)