Right, let’s talk about ConfigMaps. This is where we stop hard-coding configuration details like database URLs or feature flags directly into our application code. Hard-coding is for amateurs and prototypes that accidentally get pushed to production. We’re better than that.

Think of a ConfigMap as a simple, string-based key-value dictionary that you can hand to your application running in Kubernetes. It’s not a fancy database; it’s more like a stack of sticky notes you can pass to your Pod. The crucial thing to remember: ConfigMaps are for non-sensitive configuration data. We’re talking database URLs (db-service.prod.svc.cluster.local), config file contents, environment names (“dev”, “staging”), and other mundane details. If you put a password in here, I will find out, and I will be very disappointed in you. For secrets, we have another tool, which we’ll get to shortly.

Creating Your First ConfigMap

You can create a ConfigMap from literal values, a file, or even a directory of files. Let’s start with the literal approach. It’s great for quick tests and small bits of config.

# configmap-literal.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
data:
  APP_ENV: "production"
  LOG_LEVEL: "DEBUG"
  UI_PROPERTIES: |
    background.color=blue
    window.size=large

Notice the | for UI_PROPERTIES. That’s a YAML block scalar, letting you shove a whole blob of text (like a snippet of a properties file or JSON) into a single key. It’s incredibly handy.

Now, the more common way: creating a ConfigMap from a file. Let’s say you have an existing config.properties file you want to bring in.

# First, here's the file
cat > config.properties <<EOF
server.port=8080
server.host=0.0.0.0
EOF

# Now create the ConfigMap, magically using the file's contents
kubectl create configmap my-app-file-config --from-file=./config.properties

Kubectl will name the key after the filename itself (config.properties). You can also be more explicit and specify the key name: --from-file=my-key=./config.properties.

Using ConfigMaps in Pods: The Environment Variable Way

Creating a ConfigMap is useless if your app can’t see it. The most straightforward way to consume ConfigMap data is by populating environment variables in your container. It’s dead simple and works with any application that reads from the environment.

# pod-using-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
    - name: my-app
      image: busybox:1.28
      command: ['sh', '-c', 'echo "Environment: $APP_ENV, Log Level: $LOG_LEVEL" && sleep 3600']
      env:
        - name: APP_ENV # The name of the env var in the container
          valueFrom:
            configMapKeyRef:
              name: my-app-config    # The name of the ConfigMap
              key: APP_ENV           # The specific key to pull from
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: my-app-config
              key: LOG_LEVEL

This is precise and explicit. You’re saying exactly which key from which ConfigMap goes into which environment variable. It’s a bit verbose, but clarity is a feature.

Using ConfigMaps as Volumes: The Power Move

While environment variables are easy, they have a downside: if you update the ConfigMap, the environment variables in already-running Pods are not updated. They’re injected once at startup. This is a classic “well, actually” moment in Kubernetes that trips everyone up.

For configuration that can change during the lifetime of a Pod (and should be reloaded by the application), you must use a ConfigMap volume. This mounts the entire ConfigMap as files inside your container’s filesystem. The killer feature? When you update the ConfigMap, Kubernetes eventually updates the files in the volume. It’s not instantaneous, but it happens.

# pod-using-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: configmap-volume-demo-pod
spec:
  containers:
    - name: my-app
      image: nginx:alpine
      volumeMounts:
        - name: app-config-volume
          mountPath: /etc/appconfig
  volumes:
    - name: app-config-volume
      configMap:
        name: my-app-file-config  # This ConfigMap was created from a file

In this example, the entire contents of the my-app-file-config ConfigMap will be mounted into the /etc/appconfig directory. Each key becomes a filename, and the value becomes the file’s content. So, you’d have a file at /etc/appconfig/config.properties containing your server.port=8080 text. Your application can now use a library to watch this file for changes and reload its configuration on the fly. This is how the grown-ups do it.

The Rough Edges and Pitfalls

No tool is perfect, and ConfigMaps have their quirks. First, as mentioned, environment variables are static. Don’t expect them to change.

Second, there’s a size limit. The data section of a ConfigMap (and its cousin, the Secret) is backed by an etcd key-value store. By default, the total size of the data field is limited to 1 MiB. For most configuration, this is a non-issue. If you hit this, you’re probably doing something wrong, like trying to store a massive certificate bundle or a small image. Use a proper volume for that.

Third, and this is a biggie: ordering in envFrom is not guaranteed. You can use envFrom to import all keys from a ConfigMap as environment variables at once. It’s convenient, but the keys are processed alphabetically. If you have keys that depend on each other (e.g., PATH=$JAVA_HOME/bin:$PATH), you’re in for a world of pain because JAVA_HOME might be set after PATH, rendering it useless. Never depend on ordering with envFrom.

Finally, remember that a Pod must be able to find its ConfigMap to start. If you reference a ConfigMap that doesn’t exist (my-app-config-mispelled), your Pod will remain stuck in CreateContainerConfigError until you create that ConfigMap. It’s Kubernetes’ way of saying, “I have no idea what you’re talking about.” Always double-check your names.