ConfigMaps and Secrets

Create ConfigMaps and Secrets from literals, files and env files, inject them as environment variables or mounted files, and know which changes ever reach a running Pod.

Workloads · 15%40 min2 tasks

After this lesson

  • 01You can create a ConfigMap or Secret from literals, a file or an env file in one command, and decode any Secret value.
  • 02You can inject one key with env.valueFrom, a whole object with envFrom, and files with a configMap or secret volume, including items and subPath.
  • 03You can say which consumption methods pick up an update, and what immutable: true changes.

This lesson covers the competency Use ConfigMaps and Secrets to configure applications. Exam tasks here are short and very literal: a named object with named keys, consumed in a specific way, by a specific container. The grader reads the object, then the Pod spec, and often runs env or cat inside the container. Every detail in the question is checkable, so read it twice.

Create them imperatively

One command per source typebash
# ConfigMaps
kubectl -n wl-config create configmap app-config --from-literal=APP_MODE=production --from-literal=APP_COLOR=blue
kubectl -n wl-config create configmap nginx-conf --from-file=default.conf=./site.conf   # key=path sets the key name
kubectl -n wl-config create configmap app-env --from-env-file=./app.env                  # one key per KEY=VALUE line
kubectl -n wl-config create configmap scripts --from-file=./scripts/                      # one key per file in the directory

# Secrets: same flags, plus a type
kubectl -n wl-config create secret generic db --from-literal=username=app --from-literal=password='s3cr3t!'
kubectl -n wl-config create secret tls web-tls --cert=tls.crt --key=tls.key
kubectl -n wl-config create secret docker-registry regcred --docker-server=registry.example.com --docker-username=ci --docker-password='token'

# Look before you mount
kubectl -n wl-config describe configmap app-config
kubectl -n wl-config get secret db -o yaml

With --from-file the key is the file's base name unless you write key=path; the value is the whole file. With --from-env-file each line becomes its own key, and quotes are kept literally, so A="x" stores the quotes too. Mixing up the two is the most common reason a mounted file or a variable comes out wrong.

Secret typeCreated withRequired keysUsed by
Opaquecreate secret genericAnyYour applications
kubernetes.io/tlscreate secret tls --cert --keytls.crt, tls.keyIngress and Gateway TLS, webhooks
kubernetes.io/dockerconfigjsoncreate secret docker-registry.dockerconfigjsonspec.imagePullSecrets or a ServiceAccount's imagePullSecrets
kubernetes.io/basic-authYAMLusername, passwordTools that understand the convention
kubernetes.io/service-account-tokenYAML with an annotationFilled in by the control planeLegacy long-lived tokens; prefer kubectl create token

base64 is an encoding, not protection

Reading and writing Secret valuesbash
kubectl -n wl-config get secret db -o jsonpath='{.data.password}' | base64 -d; echo
echo -n 's3cr3t!' | base64        # -n matters: without it the trailing newline is encoded too
kubectl -n wl-config create secret generic db2 --from-literal=password='s3cr3t!' --dry-run=client -o yaml

In YAML, data takes base64 values and stringData takes plain text that the API server encodes on write; stringData is never returned on read. Secrets sit in etcd unencrypted unless the API server has an encryption configuration (covered in the architecture module), and anyone allowed to create Pods in a namespace can read every Secret there by mounting it. RBAC on Secrets and on Pod creation is the real control.

Environment variables: one key, or every keyyaml
apiVersion: v1
kind: Pod
metadata:
  name: env-demo
  namespace: wl-config
spec:
  containers:
    - name: app
      image: busybox:1.36
      command: ["sleep", "3600"]
      env:
        - name: MODE                  # one key, under a new name
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_MODE
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: db
              key: password
      envFrom:                        # every key becomes a variable
        - configMapRef:
            name: app-config
        - prefix: DB_                 # username becomes DB_username
          secretRef:
            name: db

If a referenced object or key is missing, the container does not start and the Pod shows CreateContainerConfigError; kubectl describe pod names the missing piece. Add optional: true to the reference only when the question allows the value to be absent. A name set under env wins over the same name from envFrom.

Files: a whole object, selected keys, or one file with subPathyaml
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          volumeMounts:
            - name: conf                 # one file dropped into an existing directory
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: default.conf
            - name: creds                # the whole Secret as a directory of files
              mountPath: /etc/creds
              readOnly: true
      volumes:
        - name: conf
          configMap:
            name: nginx-conf             # configMap uses "name" ...
            items:                       # only these keys, under these file names
              - key: default.conf
                path: default.conf
        - name: creds
          secret:
            secretName: db               # ... secret uses "secretName"
            defaultMode: 0400            # octal in YAML; the API stores it as 256

Mounting a volume on a directory hides whatever the image had there. That is fine for /etc/creds and harmful for /etc/nginx. When you must add one file to a directory that already has content, use subPath, and accept the trade-off in the next table.

Consumed asSees an update?What to do
env / envFromNo. Read once when the container starts.kubectl rollout restart deploy/<name>
Volume (whole object or items)Yes, after the kubelet's next sync, usually within a minute or two. The app must re-read the file.Wait, or restart if the app caches config
Volume with subPathNever.Restart the Pod
immutable: trueThe object cannot change at all.Delete, recreate, restart consumers

Setting immutable: true on a ConfigMap or Secret is a one-way door: you cannot unset it, only delete the object. In exchange the kubelet stops watching it, which takes real load off the API server on large clusters, and no one can change configuration under a running app by accident.

In the docs · the tab you get on exam day

Taskwl-config-1
Workloads5%~7 min

context · kubectl config use-context kind-cka

Configure a Deployment from a ConfigMap and a Secret

In namespace wl-config: create a ConfigMap app-config with the keys APP_MODE=production and APP_COLOR=blue, and a Secret app-secret of type Opaque with the key DB_PASSWORD=s3cr3t-pass. Then create a Deployment app with 2 replicas, image busybox:1.36, container name app, running sleep 3600. The container must get an environment variable MODE from the key APP_MODE of app-config, every key of app-secret as an environment variable, and every key of app-config as a file under /etc/app.
  1. 01

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-config-1/setup | bash
  2. 02

    Solve it in your terminal

    Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under /tmp/cka/.

  3. 03

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-config-1/verify | bash
    Counts toward your readiness score.
  4. 04

    Clean up

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-config-1/cleanup | bash
Taskwl-config-2
Workloads5%~7 min

context · kubectl config use-context kind-cka

Replace a config file and mount a Secret with strict permissions

A replacement nginx server block is in /tmp/cka/wl-config/default.conf. In namespace wl-config, create a ConfigMap proxy-conf from that file with the key default.conf, and a Secret proxy-token with the key token set to abc123. Then create a Pod proxy (image nginx:1.27) in which the ConfigMap's file replaces /etc/nginx/conf.d/default.conf, so that http://localhost:8080/healthz inside the Pod returns healthy, and the Secret is available as the file /etc/proxy/token with permissions 0400.
  1. 01

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-config-2/setup | bash
  2. 02

    Solve it in your terminal

    Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under /tmp/cka/.

  3. 03

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-config-2/verify | bash
    Counts toward your readiness score.
  4. 04

    Clean up

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-config-2/cleanup | bash

Finished reading?

0 of 2 tasks passed. Readiness counts tasks, so run them before you move on.