ConfigMaps are one of the most practical ways to decouple configuration from container images in Kubernetes. They are designed for non-sensitive configuration data and can be consumed in different ways: as environment variables, as command arguments, or as files mounted into a container.
In this article, we focus on one very useful pattern: mounting a ConfigMap as a volume.
This approach is especially helpful when your application expects configuration files, scripts, or property files instead of plain environment variables.
Why mount a ConfigMap as a volume?
A ConfigMap stores key-value pairs. Kubernetes itself does not care whether a value looks like a single-line property or a full file. What matters is how the Pod consumes it.
When you mount a ConfigMap as a volume:
- each key becomes a file name
- each value becomes the file content
- the files appear inside the container under the mount path you choose
This is ideal for cases such as:
- application config files
- startup or helper scripts
.properties,.json,.yaml, or.jsfiles- file-based settings that your application reads at runtime
Example ConfigMap
Below is a ConfigMap that contains:
- a file named
color.txt - a file named
hello-from-green.js - a value named
COLOR_CONFIG_PATHthat we will expose as an environment variable
apiVersion: v1
kind: ConfigMap
metadata:
name: green-config
data:
color.txt: green
hello-from-green.js: |
console.log("Hello from green")
console.log("The green ConfigMap is mounted correctly")
COLOR_CONFIG_PATH: /mount/config/color.txt
Example Pod
In the Pod below:
COLOR_CONFIG_PATHis injected as an environment variable usingconfigMapKeyRef- the whole ConfigMap is mounted as a read-only volume at
/mount/config
apiVersion: v1
kind: Pod
metadata:
name: green-color-api
labels:
app: green-color-api
spec:
containers:
- name: api
image: node:20-alpine
command: ["sh", "-c", "sleep 3600"]
env:
- name: COLOR_CONFIG_PATH
valueFrom:
configMapKeyRef:
name: green-config
key: COLOR_CONFIG_PATH
volumeMounts:
- name: color-config
mountPath: /mount/config
readOnly: true
volumes:
- name: color-config
configMap:
name: green-config
What happens inside the container?
Once the Pod is running, the mounted directory contains files created from the ConfigMap keys.
kubectl exec -it green-color-api -- sh
ls -la /mount/config
cat /mount/config/color.txt
node /mount/config/hello-from-green.js
printenv COLOR_CONFIG_PATH
You should see files similar to these:
/mount/config/color.txt
/mount/config/hello-from-green.js
/mount/config/COLOR_CONFIG_PATH
And the environment variable will contain:
/mount/config/color.txt
That shows an important detail: if you mount the entire ConfigMap as a volume, then all keys become files, including values that you may also expose as environment variables.
A cleaner pattern: split environment variables and files
The transcript demonstrates a mixed ConfigMap first, then shows a cleaner alternative: split the data into two ConfigMaps.
That is often easier to maintain.
For example:
ConfigMap for environment variables
apiVersion: v1
kind: ConfigMap
metadata:
name: green-vars
data:
COLOR_CONFIG_PATH: /mount/config/color.txt
ConfigMap for files
apiVersion: v1
kind: ConfigMap
metadata:
name: green-files
data:
color.txt: green
hello-from-green.js: |
console.log("Hello from green")
console.log("The green ConfigMap is mounted correctly")
Pod using both
apiVersion: v1
kind: Pod
metadata:
name: green-color-api
spec:
containers:
- name: api
image: node:20-alpine
command: ["sh", "-c", "sleep 3600"]
envFrom:
- configMapRef:
name: green-vars
volumeMounts:
- name: color-config
mountPath: /mount/config
readOnly: true
volumes:
- name: color-config
configMap:
name: green-files
With this setup, only the file-like entries appear in /mount/config, while the environment variable is injected separately.
Useful behavior to know
1. Mounted ConfigMaps are eventually refreshed
If a ConfigMap mounted as a volume is updated, Kubernetes eventually refreshes the projected files in the container. However, the change is not always instant. The kubelet checks periodically and also relies on its cache, so the delay can be around the kubelet sync period plus cache delay.
In contrast, ConfigMap values injected as environment variables are not updated automatically. Those usually require a Pod restart or rollout.
2. subPath disables automatic updates
If you mount a single file from a ConfigMap using subPath, that mounted file does not receive ConfigMap updates automatically.
That catches many teams by surprise.
3. Mounting hides existing files in that directory
If your image already contains files in the target directory, mounting a ConfigMap there makes those original files inaccessible from inside the container for that mount path.
So pick the mount path carefully.
4. You can mount only selected keys
You do not have to expose every key as a file. Kubernetes allows you to map only selected keys with items, and even choose custom file paths.
volumes:
- name: color-config
configMap:
name: green-files
items:
- key: color.txt
path: settings/color.txt
This creates the file at:
/mount/config/settings/color.txt
5. ConfigMaps are not for secrets
ConfigMaps are intended for non-confidential data. If the data is sensitive, such as passwords, tokens, or private keys, use a Secret instead.
6. ConfigMaps have a size limit
A single ConfigMap cannot exceed 1 MiB. For larger configuration payloads, it is usually better to store files elsewhere or use a different configuration strategy.
7. Optional references are supported
You can mark a ConfigMap reference as optional. In that case, if the ConfigMap or a referenced key does not exist, Kubernetes can still start the Pod, with the mounted content or env value left empty.
This can be useful for feature flags or environment-specific overrides.
8. Immutable ConfigMaps can be a good production choice
Kubernetes supports immutable: true for ConfigMaps. This is useful when configuration should not change after deployment. It helps prevent accidental updates and can reduce load on the API server in clusters with many ConfigMap mounts.
apiVersion: v1
kind: ConfigMap
metadata:
name: green-files-v1
data:
color.txt: green
immutable: true
If you need to change an immutable ConfigMap, the usual approach is to create a new ConfigMap and update the workload to reference the new name.
Practical recommendations
Here are the main takeaways:
- Use ConfigMaps for non-sensitive configuration.
- Use Secrets for credentials and confidential values.
- Mount ConfigMaps as volumes when your app expects files.
- Use environment variables when the app expects simple scalar values.
- Split file-based config and env vars into separate ConfigMaps when that improves clarity.
- Avoid mounting over directories that already contain important files.
- Be careful with
subPathif you expect live updates. - Consider immutable ConfigMaps for stable production configuration.
Conclusion
Mounting ConfigMaps as volumes is a clean and flexible way to provide file-based configuration to containers.
The mental model is simple:
- ConfigMap keys become file names
- ConfigMap values become file contents
- the Pod decides where those files appear
That makes this pattern especially useful for scripts, property files, JSON configs, and other file-oriented application settings.
A mixed ConfigMap can work, but in real projects it is often clearer to separate:
- one ConfigMap for environment variables
- one ConfigMap for mounted files
That small bit of structure can make debugging and maintenance much easier over time.
References
- Kubernetes: Configure a Pod to Use a ConfigMap - kubernetes[.]io/docs/tasks/configure-pod-container/configure-pod-configmap/
- Kubernetes: ConfigMaps - kubernetes[.]io/docs/concepts/configuration/configmap/
- Kubernetes: Updating Configuration via a ConfigMap - kubernetes[.]io/docs/tutorials/configuration/updating-configuration-via-a-configmap/
- Kubernetes: Security Checklist - kubernetes[.]io/docs/concepts/security/security-checklist/