Kubernetes ConfigMap with Examples

Tested on Rocky Linux 10.2 (Red Quartz) workstation
Package kubectl 1.36.3
Applies to Any host with kubectl configured; any Kubernetes cluster
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 Create ConfigMaps from literals, files, env files, and YAML; inject one key as an environment variable; import all keys with envFrom; mount keys as read-only files with optional items; and mark ConfigMaps immutable. Does not cover detailed rollout automation, application reload controllers, or advanced update-propagation tuning, or Secret creation.
Related guides Kubernetes volumes

A ConfigMap keeps application settings out of the container image so the same build can run in development, staging, and production. This walkthrough uses one small app configuration—APP_MODE, LOG_LEVEL, and an application.properties file—and consumes it three ways: one mapped environment variable, every key through envFrom, and files on a read-only volume.


What Is a Kubernetes ConfigMap?

A ConfigMap stores non-confidential configuration as key-value data. Pods can read those keys as environment variables, command arguments, or files on a volume. ConfigMaps are namespace-scoped, and the ConfigMap must exist in the same namespace as the Pod that references it.

Use Kubernetes Secrets for credentials, tokens, and private keys. ConfigMaps are for settings that are safe to store in plain text.

ConfigMaps expose two data fields:

Field Intended content
data UTF-8 text values
binaryData Base64-encoded binary values

This article uses data only. binaryData follows the same consumption patterns when you need to ship small binary blobs such as a TLS certificate bundle without putting raw bytes in data.

A ConfigMap cannot contain more than 1 MiB of data. Use a persistent volume, object storage, database, or file service for larger configuration assets.

Create a dedicated namespace for the examples:

bash
kubectl create namespace configmap-lab

Sample output:

output
namespace/configmap-lab created

Create ConfigMaps

Create from literal values

Literal values suit a handful of scalar settings. Each --from-literal flag becomes one key in the ConfigMap.

bash
kubectl create configmap app-config -n configmap-lab --from-literal=APP_MODE=development --from-literal=LOG_LEVEL=info

Sample output:

output
configmap/app-config created

Repeated --from-literal options add multiple keys in a single object. Confirm the ConfigMap exists:

bash
kubectl get configmap app-config -n configmap-lab

Sample output:

output
NAME         DATA   AGE
app-config   2      0s

The DATA column shows two keys. Inspect the stored values:

bash
kubectl describe configmap app-config -n configmap-lab

Sample output:

output
Name:         app-config
Namespace:    configmap-lab
Labels:       <none>
Annotations:  <none>

Data
====
APP_MODE:
----
development

LOG_LEVEL:
----
info

BinaryData
====

Events:  <none>

For a manifest-friendly view, dump the live object:

bash
kubectl get configmap app-config -n configmap-lab -o yaml

Sample output:

output
apiVersion: v1
data:
  APP_MODE: development
  LOG_LEVEL: info
kind: ConfigMap
metadata:
  creationTimestamp: "2026-07-26T15:41:52Z"
  name: app-config
  namespace: configmap-lab
  resourceVersion: "459899"
  uid: c8c738a7-2e63-4c38-b106-0404e450a421

The data map holds the keys you passed on the command line.

Create from files and directories

File-based creation is the usual path for configuration files. Start with a sample properties file on your workstation:

text
server.port=8080
app.name=demo

Save it as application.properties, then create a ConfigMap where the filename becomes the key:

bash
kubectl create configmap app-files -n configmap-lab --from-file=application.properties

Sample output:

output
configmap/app-files created

When you omit an explicit key name, Kubernetes uses the basename of the file as the ConfigMap key. To store the same file under a different key, use key=path syntax:

bash
kubectl create configmap app-files-keyed -n configmap-lab --from-file=app.properties=application.properties

Sample output:

output
configmap/app-files-keyed created

Compare the resulting keys:

bash
kubectl get configmap app-files -n configmap-lab -o yaml

Sample output:

output
apiVersion: v1
data:
  application.properties: |
    server.port=8080
    app.name=demo
kind: ConfigMap
metadata:
  name: app-files
  namespace: configmap-lab

The first object uses the filename as the key. Dump the keyed variant to see the difference:

bash
kubectl get configmap app-files-keyed -n configmap-lab -o yaml

Sample output:

output
apiVersion: v1
data:
  app.properties: |
    server.port=8080
    app.name=demo
kind: ConfigMap
metadata:
  name: app-files-keyed
  namespace: configmap-lab

The file content becomes the value. With app.properties=application.properties, the key is app.properties even though the source file on disk keeps its original name.

Point --from-file at a directory to load every regular file as a separate key. Create the directory and sample files first:

bash
mkdir -p config-dir
bash
printf 'database.host=db.example\n' > config-dir/database.conf
bash
printf 'log.level=info\n' > config-dir/logging.conf

Then create the ConfigMap:

bash
kubectl create configmap app-dir -n configmap-lab --from-file=./config-dir/

Sample output:

output
configmap/app-dir created

Each regular file whose basename is a valid ConfigMap key becomes one entry. Subdirectories, symbolic links, devices, and other non-regular entries are ignored.

Create from an environment file

An env file is a line-oriented KEY=value list. Create app.env:

text
APP_MODE=production
LOG_LEVEL=warning

Import it with --from-env-file:

bash
kubectl create configmap app-env -n configmap-lab --from-env-file=app.env

Sample output:

output
configmap/app-env created

--from-env-file reads line-oriented KEY=value entries. Blank lines and lines beginning with # are ignored, while quotation marks are preserved as part of the value. Use --from-file when JSON, YAML, properties, or another configuration file should remain one complete ConfigMap value.

Define a ConfigMap in YAML

Declarative manifests are easier to review in Git and apply with kubectl apply. The example below mixes scalar keys with a multiline configuration file:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-yaml
  namespace: configmap-lab
data:
  APP_MODE: staging
  LOG_LEVEL: debug
  application.properties: |
    server.port=9090
    app.name=demo-yaml

Apply the manifest:

bash
kubectl apply -f app-config-yaml.yaml

Sample output:

output
configmap/app-config-yaml created

The pipe (|) block under application.properties preserves newlines so the mounted file keeps its structure.

For binary content, use binaryData with base64-encoded values instead of placing raw bytes in data.

Generate YAML with client-side dry run

Generate reusable YAML from imperative input without creating the object:

bash
kubectl create configmap app-config-dry -n configmap-lab --from-literal=APP_MODE=production --dry-run=client -o yaml

Sample output:

output
apiVersion: v1
data:
  APP_MODE: production
kind: ConfigMap
metadata:
  name: app-config-dry
  namespace: configmap-lab

Redirect that output into a file when you want a starting manifest for version control.


Use ConfigMaps as Environment Variables

Inject one key with configMapKeyRef

Use env[].valueFrom.configMapKeyRef when the application expects one variable with a specific name. The container variable does not have to match the ConfigMap key.

The Pod below maps ConfigMap key LOG_LEVEL to environment variable APP_LOG_LEVEL:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: env-single
  namespace: configmap-lab
spec:
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh", "-c", "echo APP_LOG_LEVEL=$APP_LOG_LEVEL; sleep 3600"]
    env:
    - name: APP_LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: LOG_LEVEL
  restartPolicy: Never

Apply the Pod:

bash
kubectl apply -f env-single.yaml

Sample output:

output
pod/env-single created

Wait until the container is ready before checking variables:

bash
kubectl wait --for=condition=Ready pod/env-single -n configmap-lab --timeout=60s

Sample output:

output
pod/env-single condition met

Read the container log to confirm the mapping:

bash
kubectl logs env-single -n configmap-lab

Sample output:

output
APP_LOG_LEVEL=info

You can also read the variable directly inside the container:

bash
kubectl exec env-single -n configmap-lab -- printenv APP_LOG_LEVEL

Sample output:

output
info

The value info came from the LOG_LEVEL key in app-config, even though the process sees APP_LOG_LEVEL.

Import all keys with envFrom

When the application already expects environment variables that match ConfigMap keys, envFrom is shorter than listing each env entry.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: env-from
  namespace: configmap-lab
spec:
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh", "-c", "env | sort; sleep 3600"]
    envFrom:
    - configMapRef:
        name: app-config
  restartPolicy: Never

Apply the Pod:

bash
kubectl apply -f env-from.yaml

Sample output:

output
pod/env-from created

Wait for Ready, then inspect the environment:

bash
kubectl wait --for=condition=Ready pod/env-from -n configmap-lab --timeout=60s

Sample output:

output
pod/env-from condition met

Every suitable key in app-config becomes an environment variable with the same name. The log shows the imported values among the usual Kubernetes service variables:

bash
kubectl logs env-from -n configmap-lab

Sample output (trimmed):

output
APP_MODE=development
LOG_LEVEL=info

Prefer explicit env entries when you need to rename keys or import only a subset.

For how env and envFrom interact with command, args, and $(VAR) substitution, see commands, args and environment variables.

Add an envFrom prefix

When every variable should share a common prefix, add prefix alongside configMapRef. The prefix and configMapRef fields are siblings under an EnvFromSource:

yaml
envFrom:
- prefix: APP_
  configMapRef:
    name: app-config

With prefix: APP_, keys APP_MODE and LOG_LEVEL become environment variables APP_APP_MODE and APP_LOG_LEVEL.


Mount ConfigMaps as Files

Some applications read configuration from a file path rather than the environment. A ConfigMap volume turns each key into a filename and each value into file content. The mount is read-only.

Mount every key

Create a ConfigMap that includes scalar keys and a properties file, then mount it at /etc/app-config. Save both resources in volume-mount.yaml:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-mount-config
  namespace: configmap-lab
data:
  APP_MODE: production
  LOG_LEVEL: warning
  application.properties: |
    server.port=8080
    app.name=demo
---
apiVersion: v1
kind: Pod
metadata:
  name: volume-mount
  namespace: configmap-lab
spec:
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - name: app-config-vol
      mountPath: /etc/app-config
  volumes:
  - name: app-config-vol
    configMap:
      name: app-mount-config
  restartPolicy: Never

Define the volume once at Pod scope. Every container that needs the files adds its own volumeMounts entry pointing at that volume name.

Apply the manifest:

bash
kubectl apply -f volume-mount.yaml

Sample output:

output
configmap/app-mount-config created
pod/volume-mount created

Wait for the Pod, then list the mounted files:

bash
kubectl wait --for=condition=Ready pod/volume-mount -n configmap-lab --timeout=60s

Sample output:

output
pod/volume-mount condition met

List the files under the mount path:

bash
kubectl exec volume-mount -n configmap-lab -- ls -l /etc/app-config

Sample output:

output
total 0
lrwxrwxrwx    1 root     root            15 Jul 26 15:42 APP_MODE -> ..data/APP_MODE
lrwxrwxrwx    1 root     root            16 Jul 26 15:42 LOG_LEVEL -> ..data/LOG_LEVEL
lrwxrwxrwx    1 root     root            29 Jul 26 15:42 application.properties -> ..data/application.properties

Read the properties file the application would parse:

bash
kubectl exec volume-mount -n configmap-lab -- cat /etc/app-config/application.properties

Sample output:

output
server.port=8080
app.name=demo

Symlinks under ..data are normal—the kubelet projects ConfigMap keys as individual files in the mount path.

Select and rename keys

By default a ConfigMap volume exposes every key. Use volumes[].configMap.items to select keys and rename the target filename:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-items
  namespace: configmap-lab
spec:
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh", "-c", "ls -l /etc/app-config; cat /etc/app-config/app.properties; sleep 3600"]
    volumeMounts:
    - name: app-config-vol
      mountPath: /etc/app-config
  volumes:
  - name: app-config-vol
    configMap:
      name: app-mount-config
      items:
      - key: application.properties
        path: app.properties
        mode: 0440
  restartPolicy: Never

Only application.properties is mounted, renamed to app.properties. Keys not listed in items do not appear in the directory.

Apply the Pod:

bash
kubectl apply -f volume-items.yaml

Sample output:

output
pod/volume-items created

Set projected file permissions

Wait for the Pod before reading logs or checking permissions:

bash
kubectl wait --for=condition=Ready pod/volume-items -n configmap-lab --timeout=60s

Sample output:

output
pod/volume-items condition met

The container startup command lists the mount and prints the file:

bash
kubectl logs volume-items -n configmap-lab

Sample output:

output
total 0
lrwxrwxrwx    1 root     root            21 Jul 26 15:42 app.properties -> ..data/app.properties
server.port=8080
app.name=demo

The symlink shows lrwxrwxrwx, but the configured mode applies to the projected target file rather than the symlink itself. stat on the symlink path reports 777; verify the target file under ..data:

bash
kubectl exec volume-items -n configmap-lab -- stat -c '%a %n' /etc/app-config/..data/app.properties

Sample output:

output
440 /etc/app-config/..data/app.properties

Avoid hiding existing files with directory mounts

Volume mounts replace the entire mount path, so a full-directory mount can hide files baked into the image. When you need to overlay a single file without hiding the rest of a directory—such as replacing /etc/nginx/nginx.conf while keeping other files in /etc/nginx—use subPath on the volume mount. See subPath volume examples for that pattern.


Understand ConfigMap Update Behavior

ConfigMaps consumed through env or envFrom are captured when the container starts and require Pod replacement or restart to receive changed values. ConfigMaps mounted as full volumes are updated eventually by the kubelet, although the application may still need to reload the file. ConfigMap files mounted with subPath do not receive updates.

Full ConfigMap volume projections update eventually, environment variables do not, and subPath is excluded from automatic projection updates. For rollout timing, reload controllers, and propagation details, see update ConfigMaps and Secrets without Pod restart.


Create an Immutable ConfigMap

Set immutable: true when configuration should never change in place. Immutable ConfigMaps protect configuration from accidental in-place changes. On clusters with very large numbers of ConfigMap mounts, they can also reduce API-server load because kubelets do not need to watch those objects for data changes.

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-immutable
  namespace: configmap-lab
data:
  APP_MODE: release
immutable: true

Apply the manifest:

bash
kubectl apply -f app-config-immutable.yaml

Sample output:

output
configmap/app-config-immutable created

An attempt to patch data fails:

bash
kubectl patch configmap app-config-immutable -n configmap-lab --type merge -p '{"data":{"APP_MODE":"changed"}}'

Sample output:

output
The ConfigMap "app-config-immutable" is invalid: data: Forbidden: field is immutable when `immutable` is set

You cannot remove immutable from an existing ConfigMap. To ship new settings, create a ConfigMap with a new name and update the Pod or workload template to reference it.


Choose a Consumption Method and Fix Common Errors

Requirement Method
Inject one selected value configMapKeyRef in env
Import many variables envFrom with configMapRef
Provide a complete configuration file ConfigMap volume
Select or rename mounted files Volume items
Prevent in-place data changes immutable: true
Symptom Likely cause Fix
ConfigMap not found Wrong name or namespace Confirm the object with kubectl get configmap -n <namespace>; create it in the Pod namespace before the Pod starts
Required key does not exist Typo in configMapKeyRef.key or items[].key Run kubectl describe configmap <name> and match the key exactly
Mounted files hide existing image files Volume mounted over a directory the image already uses Mount into a dedicated path such as /etc/app-config, or use subPath for a single file
Application expects a file but receives an environment variable Wrong consumption method Switch from env to a ConfigMap volume, or the reverse
Immutable ConfigMap cannot be edited immutable: true blocks updates Create a new ConfigMap name and update the workload reference

What's Next


References


Summary

You created ConfigMaps from literals, files, env files, and YAML, then verified keys with kubectl get, describe, and -o yaml. The same app-config object fed three consumption paths: configMapKeyRef mapped LOG_LEVEL to APP_LOG_LEVEL, envFrom imported every key as a matching environment variable, and a ConfigMap volume projected keys as read-only files under /etc/app-config.

Volume mounts replace the entire mount path, so a full-directory mount can hide files baked into the image. Use a dedicated directory or subPath when only one file should change. Immutable ConfigMaps reject in-place edits—plan versioned names and workload updates instead of patching data after the fact.

For credentials, switch to Secrets. For timing around rollouts after configuration changes, read how env vars, mounted files, and projected volumes pick up updates in the companion guide on updating ConfigMaps without unnecessary restarts.


Frequently Asked Questions

1. What is the difference between a ConfigMap and a Secret?

ConfigMaps store non-confidential configuration as plain text key-value data. Secrets are intended for sensitive values such as passwords and tokens. Both can be consumed as environment variables or mounted files, but neither encrypts data at rest in etcd by default.

2. Can a Pod in one namespace use a ConfigMap from another namespace?

No. A Pod can only reference ConfigMaps in the same namespace. Copy or recreate the ConfigMap in the target namespace, or use a controller that syncs configuration across namespaces.

3. Does the environment variable name have to match the ConfigMap key?

No. With configMapKeyRef you set the env name in the Pod spec and point it at any key in the ConfigMap. With envFrom, the environment variable name matches the ConfigMap key unless you add a prefix.

4. Are ConfigMap volume mounts writable?

No. A volume backed by a ConfigMap is mounted read-only. Applications that need to edit configuration locally must copy files elsewhere or use a different volume type.

5. What happens when I mount a ConfigMap over an existing directory?

The mount hides files that already exist at that path inside the container image. Mount into a dedicated directory such as /etc/app-config, or use subPath when you need to replace a single file without masking the rest of the directory.

6. Can I change an immutable ConfigMap?

No. When immutable is true, data and binaryData cannot be patched. Create a new ConfigMap with a different name and update the workload to reference it.
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)