ConfigMaps

Externalize application configuration using ConfigMaps. Mount configuration as environment variables or files.

7 min read

ConfigMaps

In the Previous Tutorial, we learned about Services and how to expose our apps. Now let's talk about something every developer deals with — configuration.

Hardcoding configuration in container images is a terrible idea. Every time you want to change a database URL or a log level, you'd have to rebuild the entire image. That's like reprinting an entire book just to fix a typo.

ConfigMaps solve this — they store configuration data separately from your application and inject it at runtime. Change the config, not the code.

What is a ConfigMap?

So it's just a key-value store?

Pretty much! A ConfigMap is a Kubernetes object that stores non-sensitive configuration data as key-value pairs. Your application reads this configuration without knowing (or caring) where it comes from.

Use cases:

  • Environment-specific settings (dev, staging, prod)
  • Feature flags
  • Configuration files (nginx.conf, application.properties)
  • Command-line arguments

Important: ConfigMaps are for non-sensitive data only. For passwords and API keys, use Secrets (next tutorial). Please don't put your database password in a ConfigMap. Just... don't.

Create a ConfigMap

There are several ways to create a ConfigMap. Let's explore them all.

Method 1: From Literal Values

The quick and easy way — great for a few key-value pairs: kubectl create configmap app-config
--from-literal=DATABASE_HOST=db.example.com
--from-literal=DATABASE_PORT=5432
--from-literal=LOG_LEVEL=info


Check it:

```bash
kubectl get configmap app-config -o yaml

Output:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: db.example.com
  DATABASE_PORT: "5432"
  LOG_LEVEL: info

Method 2: From a File

Got a config file? You can turn the whole thing into a ConfigMap:

Create app.properties:

database.host=db.example.com
database.port=5432
log.level=info
cache.enabled=true

Create ConfigMap from file:

kubectl create configmap app-config-file --from-file=app.properties

The filename becomes the key — neat, right?

kubectl get configmap app-config-file -o yaml
data:
  app.properties: |
    database.host=db.example.com
    database.port=5432
    log.level=info
    cache.enabled=true

Method 3: From Directory

kubectl create configmap app-config-dir --from-file=./config-directory/

Each file in the directory becomes a key.

Method 4: YAML Definition (Recommended)

This is the way the pros do it — version-controlled, reviewable, and repeatable. Create configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: db.example.com
  DATABASE_PORT: "5432"
  LOG_LEVEL: info
  
  # Multi-line config file
  nginx.conf: |
    server {
      listen 80;
      server_name localhost;
      location / {
        root /usr/share/nginx/html;
        index index.html;
      }
    }

Apply:

kubectl apply -f configmap.yaml

Use ConfigMaps in Pods

Okay, I've created a ConfigMap. How does my app actually read it?

Three ways! Pick the one that fits your use case:

1. Environment Variables (Single Keys)

Inject specific keys as environment variables — the most common approach:

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: nginx
    env:
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_HOST
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_PORT

Inside the container:

kubectl exec app-pod -- env | grep DB_
DB_HOST=db.example.com
DB_PORT=5432

2. Environment Variables (All Keys)

Feeling lazy? Just inject ALL keys at once with envFrom:

apiVersion: v1
kind: Pod
metadata:
  name: app-pod-all-env
spec:
  containers:
  - name: app
    image: nginx
    envFrom:
    - configMapRef:
        name: app-config

All ConfigMap keys become environment variables automatically. Zero effort. Love it.

3. Volume Mounts (Files)

This one's interesting — you can mount ConfigMap data as actual files inside the container:

apiVersion: v1
kind: Pod
metadata:
  name: app-pod-volume
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: config-volume
      mountPath: /etc/nginx/conf.d
  volumes:
  - name: config-volume
    configMap:
      name: app-config
      items:
      - key: nginx.conf
        path: default.conf

This mounts nginx.conf from the ConfigMap as /etc/nginx/conf.d/default.conf.

Without items, all keys are mounted as files:

volumes:
- name: config-volume
  configMap:
    name: app-config

Each key becomes a file in /etc/nginx/conf.d/.

Practical Example: Custom Nginx Config

Let's do something fun — we'll serve a custom webpage using ConfigMaps. No image rebuilding required!

Create nginx-configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  index.html: |
    <!DOCTYPE html>
    <html>
    <head><title>Hello from ConfigMap!</title></head>
    <body>
      <h1>Configuration loaded from ConfigMap</h1>
      <p>This content is stored in Kubernetes, not the image.</p>
    </body>
    </html>

Create nginx-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-custom
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html
    configMap:
      name: nginx-config

Apply both:

kubectl apply -f nginx-configmap.yaml
kubectl apply -f nginx-pod.yaml

Test it:

kubectl port-forward nginx-custom 8080:80

Open http://localhost:8080. You'll see "Configuration loaded from ConfigMap" instead of the default nginx page. The content lives in Kubernetes, not in the image. How cool is that?

Update ConfigMaps

Update the ConfigMap

kubectl edit configmap nginx-config

Or apply an updated YAML file.

How Pods React

Here's something important to know:

Environment variables: Don't update automatically. The Pod must be restarted to pick up changes. It's like the Pod reads the config on startup and then forgets the source exists.

Volume mounts: Update automatically! Kubernetes syncs changes within about a minute. The Pod doesn't need to restart — it just reads the new files. Magic!

Force immediate update with volume mounts:

kubectl exec nginx-custom -- cat /usr/share/nginx/html/index.html

After editing the ConfigMap, wait ~60 seconds and check again.

Restarting Pods for Env Changes

kubectl rollout restart deployment <deployment-name>

Or delete and recreate the Pod.

Immutable ConfigMaps

Once you're sure a ConfigMap won't change, mark it as immutable. Why? Two reasons:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-immutable
data:
  setting: value
immutable: true

Benefits:

  • Kubernetes doesn't watch for changes (better performance)
  • Prevents accidental modifications

To change an immutable ConfigMap, delete and recreate it. It's like writing in permanent marker — you better be sure.

ConfigMap Size Limits

ConfigMaps have a 1MB size limit. That's plenty for config files, but if you're trying to store War and Peace in there... don't.

For larger data:

  • Use a Persistent Volume
  • Store data externally (S3, databases)
  • Split into multiple ConfigMaps

Best Practices

1. Use Descriptive Names

Future-you will thank present-you:

# Good — tells you exactly what it is
name: payment-service-config
name: redis-config-prod

# Bad — what even is this?
name: config1
name: my-config

2. Namespace Your ConfigMaps

ConfigMaps are namespaced. Create them in the same namespace as the Pods that use them.

3. Version Your ConfigMaps

Include version in the name when using immutable ConfigMaps:

name: app-config-v1
name: app-config-v2

4. Use Separate ConfigMaps

Don't put everything in one giant ConfigMap. It's like putting all your clothes in one drawer — it works until it doesn't:

# Separate concerns — clean and organized
name: database-config
name: logging-config
name: feature-flags

Inspect ConfigMaps

# List all ConfigMaps
kubectl get configmaps

# View details
kubectl describe configmap app-config

# View data
kubectl get configmap app-config -o yaml

# View specific key
kubectl get configmap app-config -o jsonpath='{.data.DATABASE_HOST}'

Clean Up

kubectl delete pod nginx-custom app-pod app-pod-all-env app-pod-volume 2>/dev/null
kubectl delete configmap app-config nginx-config app-config-file 2>/dev/null

What's Next?

ConfigMaps handle regular configuration beautifully. But what about passwords, API keys, and database credentials? You can't put those in ConfigMaps — they're stored in plain text!

In the next tutorial, you'll learn about Secrets — ConfigMap's security-conscious cousin. Let's go!

What's Next?

ConfigMaps handle regular configuration. But what about passwords, API keys, and certificates? You don't want those in plain text. In the next tutorial, you'll learn about Secrets — Kubernetes' way of managing sensitive data.