Skip to main content
RunBook Academy

KubernetesXX · ConfigurationConfiguration

Mounted volumes — ConfigMap as files inside the container

Advanced⏱ ~17 minkubectlkubeadm

What you'll learn

  • Configure a Pod that mounts a ConfigMap as files
  • Distinguish file-mount semantics from env-var semantics
  • Use subPath to mount a single key at a specific path
  • Configure the application to reload when files change

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

The file-mount consumption pattern projects ConfigMap keys as files inside a container. Unlike env vars, files update when the ConfigMap changes — but the update is eventually consistent (default ~60 seconds), and the application must detect and reload. This lesson covers the mount patterns, the timing, and the production discipline.

Mounting a ConfigMap as files

spec:
  containers:
  - name: web
    image: web:v1
    volumeMounts:
    - name: config
      mountPath: /etc/web
  volumes:
  - name: config
    configMap:
      name: web-config

The container sees every key in the ConfigMap as a file under /etc/web:

/etc/web/log_level       # contents: info
/etc/web/database_url    # contents: postgres://...
/etc/web/feature_flags   # contents: {...}
flowchart LR
    A["ConfigMap<br/>keys + values"] -->|projected as files| B["/etc/web/"]
    B --> C["Container process<br/>reads files"]

The files are tmpfs mounts managed by the kubelet. They are not regular files; they are bind mounts from the kubelet’s data directory. A df inside the container shows the mount:

tmpfs           1G  0  1G  0% /etc/web

subPath for selective mounts

volumeMounts:
- name: config
  mountPath: /etc/web/app.conf
  subPath: app.conf
volumes:
- name: config
  configMap:
    name: web-config

subPath mounts a single key as a file at the specified path. Useful when:

  • The application expects a specific filename (/etc/web/app.conf, not /etc/web/app_conf).
  • The mount path overlaps with a directory the container also writes to (a subPath mount does not hide the directory’s existing contents).
flowchart TB
    A[ConfigMap keys] -->|with subPath| B["/etc/web/app.conf<br/>(only this file)"]
    A -->|without subPath| C["/etc/web/<br/>(all keys as files)"]

items for key selection

volumes:
- name: config
  configMap:
    name: web-config
    items:
    - key: log_level
      path: log.txt
    - key: database_url
      path: db.txt

items projects a subset of keys. Each entry maps a key to a path inside the mount. Useful when the ConfigMap has more keys than the application needs.

Update semantics — eventually consistent

flowchart LR
    A["ConfigMap updated<br/>in API server"] --> B["Kubelet watches<br/>API server"]
    B --> C{Period elapsed?<br/>default syncPeriod}
    C -->|yes| D[Kubelet updates
    mount]
    C -->|no| E[Wait]
    D --> F["Container sees<br/>new file contents"]

The kubelet syncs the mount periodically. The default syncPeriod is configurable via --config-sync-period on the kubelet (typically 60s in kubeadm clusters). The mount’s contents update within that window after the ConfigMap change is observed.

Detecting the change in the application

The container sees the new file contents, but the application must detect and reload:

import time
import os

mtime = os.stat('/etc/web/log_level').st_mtime
while True:
    time.sleep(5)
    new_mtime = os.stat('/etc/web/log_level').st_mtime
    if new_mtime != mtime:
        reload_config()
        mtime = new_mtime

The kubelet updates the file’s mtime when the contents change. The application polls the mtime (or the file contents directly) and triggers a reload.

Many applications support a SIGHUP for reload:

# PID of the application process, from `ps` inside the container.
# A container's main process is usually PID 1:
APP_PID=1

# Application receives SIGHUP and re-reads config
kill -HUP "$APP_PID"

A sidecar (e.g., a Reloader) can watch the file and send SIGHUP to the main process when it changes.

flowchart TB
    A[ConfigMap updated] --> B[Kubelet updates mount]
    B --> C[File mtime changes]
    C --> D{Application<br/>detects change?}
    D -->|yes, poll| E[Reload config]
    D -->|yes, SIGHUP| E
    D -->|no| F["Application uses<br/>stale config"]

Default mode (file permissions)

volumes:
- name: config
  configMap:
    name: web-config
    defaultMode: 0644

The kubelet creates the files with the specified mode. The default is 0644 (world-readable). For sensitive files (secrets, certificates), use 0400 (owner-readable only).

Real-world patterns

Pattern: nginx config

data:
  nginx.conf: |
    events { worker_connections 1024; }
    http {
      server {
        listen 80;
        location / { proxy_pass http://backend; }
      }
    }
volumeMounts:
- name: nginx-config
  mountPath: /etc/nginx/nginx.conf
  subPath: nginx.conf
volumes:
- name: nginx-config
  configMap:
    name: web-config

nginx -s reload reads the new config without restarting the master process. The pattern: a sidecar watches the file and runs nginx -s reload on change.

Pattern: Java application.properties

data:
  application.properties: |
    spring.datasource.url=jdbc:postgresql://db/data
    spring.datasource.username=app
    logging.level.root=INFO
volumeMounts:
- name: spring-config
  mountPath: /app/config/application.properties
  subPath: application.properties

Spring Boot reads application.properties at startup; for hot reload, the application must be designed with @RefreshScope or spring-cloud-config integration. A plain Spring Boot does not reload on file change.

Pattern: TLS certificate as a file (intermediate)

data:
  tls.crt: |
    -----BEGIN CERTIFICATE-----
    ...
volumeMounts:
- name: tls
  mountPath: /etc/tls/tls.crt
  subPath: tls.crt

A TLS cert can be stored in a ConfigMap. (This is acceptable for non-secret certs and intermediate CAs; for private keys, use a Secret.) The application reads the file and uses it without restart.

Quiz

Knowledge check · 4 questions

  1. Q1. How long does it take for a mounted ConfigMap file to reflect a change in the ConfigMap?

  2. Q2. The kubelet's default sync period for ConfigMap and Secret volumes is 60 seconds, configurable via kubelet flags.

  3. Q3. Your team's web application reads a config file mounted from a ConfigMap. The application does not reload on file change. Diagnose and remediate.

    Application web reads /etc/web/app.conf at startup. The ConfigMap is updated to enable a feature. The kubelet updates the file within ~60s; the application continues with the old config.

  4. Q4. Explain subPath in a ConfigMap volume mount, and when to use it.

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Use file mounts for configuration that should update at runtime. Env vars are wrong for log levels, feature flags, or URLs that may change.
  • Test the reload path. A mounted ConfigMap that the application does not reload is a config change that does nothing.
  • Verify the kubelet’s syncPeriod. A 60-second default means 60 seconds of staleness after a ConfigMap change.
  • Use subPath when the application expects a specific filename. Mounting all keys at /etc/web/ works only if the application reads that path.
  • Set defaultMode deliberately. A 0644 mode on a Secret-mounted file is not what you want; use 0400.

File mounts are the right pattern for configuration that must update at runtime. The application must be designed to detect the change and act; the kubelet’s syncPeriod determines the propagation delay. Operators who understand the timing have ConfigMaps that work.