2025-03-22
8 min read

How to Mount a Single File in a Volume

How to Mount a Single File in a Volume

Mounting a single file into a running container is a common need. Maybe you want to inject one config file, a CA certificate, or a feature flag without replacing an entire directory. This guide shows you how to mount exactly one file using Docker and Kubernetes in a safe, repeatable way.

TLDR

  • Use Docker CLI bind mounts to map one host file to one container path: set :ro when possible.
  • In Docker Compose, use long syntax type: bind with source and target pointing to files.
  • In Kubernetes, mount a single file from a ConfigMap or Secret with subPath mapped to a file path.
  • Watch out for SELinux labels on Linux hosts :z or :Z, and file permission differences across macOS, Linux, and WSL2.

Small mental model for what happens at runtime:

Host FS                 Container FS
---------               -------------
/srv/app/config.yaml -> /app/config/config.yaml  (mounted file)
         ^ bind mount replaces only this file at target path

Prerequisites

  • Docker Desktop 4.x or Docker Engine 24.x+
  • kubectl 1.27+ and a cluster for the Kubernetes examples (kind or Minikube works)

Docker CLI: mount one file with a bind mount

You can bind mount a single file by mapping a host file to a container file path. Use read-only whenever the container does not need to write to it.

# Example: run NGINX with a custom top-level nginx.conf from the host
mkdir -p /tmp/nginx
cat > /tmp/nginx/nginx.conf <<'CONF'
events {}
http {
  server {
    listen 8080;
    location / {
      return 200 'ok from custom config';
    }
  }
}
CONF

# Map exactly one file into the container
docker run --rm -p 8080:8080 \
  -v /tmp/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
  nginx:1.27-alpine

# In another terminal, verify the config is active
curl -fsS http://localhost:8080

Why this works:

  • When the source is a file and the target is a file path, Docker mounts only that file.
  • If the target directory exists, Docker overlays the file at the target path without replacing the rest of the directory.
  • :ro keeps the container from mutating the host file.

Common variations:

# Inject an application env file
docker run --rm \
  -v $(pwd)/deploy/app.env:/app/config/app.env:ro \
  ghcr.io/examplecorp/invoice-service:1.9.3

# Trust a custom root CA
docker run --rm \
  -v /etc/ssl/mycompany.pem:/usr/local/share/ca-certificates/mycompany.pem:ro \
  alpine:3.20 sh -c "update-ca-certificates && wget https://internal.api"

Notes for Linux hosts with SELinux

On SELinux-enabled hosts, containers may be blocked from reading host files. Add a label option to the bind mount.

# :z for shared content, :Z for private content
docker run --rm \
  -v /secure/config.yaml:/app/config/config.yaml:ro,Z \
  ghcr.io/examplecorp/invoice-service:1.9.3

Docker Compose: mount one file with long syntax

Compose supports single-file binds with the long volume syntax. This is easier to read and less error prone than short source:target strings.

version: '3.9'
services:
  nginx:
    image: nginx:1.27-alpine
    ports:
      - '8080:8080'
    volumes:
      - type: bind
        source: ./ops/nginx/nginx.conf # host file
        target: /etc/nginx/nginx.conf # container file
        read_only: true

Why this is useful:

  • You only replace one file inside the container while keeping the image defaults for the rest.
  • read_only: true matches production expectations for config.

Kubernetes: mount one file with subPath from a ConfigMap

In Kubernetes you typically do not mount host files directly. Instead you mount files from a volume source like a ConfigMap or Secret. To map exactly one entry to a specific path, use subPath.

First, create a ConfigMap with multiple keys. Each key becomes a file in the volume.

kubectl create configmap web-config \
  --from-literal=nginx.conf='events {}\nhttp { server { listen 8080; location / { return 200 "ok from cm"; } } }' \
  --from-literal=extra.conf='# extra directives here'

Then mount only nginx.conf to the desired path using subPath.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: web-config
              mountPath: /etc/nginx/nginx.conf # mount a single file
              subPath: nginx.conf # choose the key to project
              readOnly: true
      volumes:
        - name: web-config
          configMap:
            name: web-config

This maps only one file, not the whole directory. The rest of /etc/nginx stays from the image.

Mount a single Secret file

You can repeat the same pattern with a Secret.

kubectl create secret generic tls-root-ca \
  --from-file=mycompany.pem=/etc/ssl/mycompany.pem
volumeMounts:
  - name: ca
    mountPath: /usr/local/share/ca-certificates/mycompany.pem
    subPath: mycompany.pem
    readOnly: true
volumes:
  - name: ca
    secret:
      secretName: tls-root-ca

Read-only, ownership, and permissions

  • Prefer read-only mounts for configuration. In Docker, use :ro. In Kubernetes, use readOnly: true.
  • Container users may differ from the file owner on the host. For Docker on Linux, you might need chown on the host or run the container with a matching UID.
  • In Kubernetes, use securityContext to run as a non-root user if the application can handle it.
securityContext:
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000

Verifying your mount

These quick checks save time when debugging.

# Inside a Docker container
docker exec -it $(docker ps --filter name=nginx -q) sh -lc \
  'ls -l /etc/nginx/nginx.conf && head -n5 /etc/nginx/nginx.conf'

# Inside a Kubernetes Pod
kubectl exec -it deploy/web -- sh -lc \
  'ls -l /etc/nginx/nginx.conf && head -n5 /etc/nginx/nginx.conf'

Troubleshooting

  • Target path is a directory: Docker may error or behave unexpectedly. Point the target to a file path, not a directory.
  • Host path does not exist: Docker will create a directory if you accidentally give a directory-like path. Double check the source points to a file.
  • SELinux denied access: use :Z or :z on Linux hosts.
  • Docker Desktop file sharing: on macOS and Windows, the source path must be under a shared location.
  • File not updating in Kubernetes: ConfigMap updates do not automatically refresh when using subPath. Roll the Pod or use a different pattern if you need live reloads.

With these patterns you can cleanly inject one file into a container for configuration, certificates, or feature flags. Start with Docker bind mounts for local development, and use Kubernetes subPath with ConfigMaps or Secrets in clusters.

Proudly Sponsored By

These amazing companies help us create free, high-quality DevOps content for the community

Want to support DevOps Daily and reach thousands of developers?

Become a Sponsor
Published: 2025-03-22|Last updated: 2025-03-22T09:00:00Z

Found an issue?