Cloud AI Campus
  • Career paths
  • Learning paths
  • Hands-on Labs
Log in Sign up

๐Ÿงช Hands-on lab · 35 min

ConfigMaps and Secrets

  1. 1. Create a ConfigMap three ways
  2. 2. Inject a ConfigMap as environment variables
  3. 3. Mount a ConfigMap as a volume
  4. 4. Create a Secret
  5. 5. Consume the Secret as an env var

Create a ConfigMap three ways

A ConfigMap is a Kubernetes object that holds key/value config data. Pods can pull from it as environment variables, command-line args, or files mounted into a volume.

There are three idiomatic ways to create one.

From a literal

kubectl create configmap sample --from-literal=message=hello

Inspect it:

kubectl get configmap sample -o yaml

The data: map has one entry: message: hello.

From a file on disk

cat config/sample.properties
kubectl create configmap sample2 --from-file=config/sample.properties

The file's name becomes the key, its contents the value:

kubectl describe configmap sample2

From a YAML manifest

cat config/config-map-3.yaml
kubectl apply -f config/config-map-3.yaml

kubectl describe configmap sample3 shows three keys: message, retries, feature.banner.

Click Verify step when all three exist.

Hint

From literal: `kubectl create configmap sample --from-literal=message=hello`. From file: `kubectl create configmap sample2 --from-file=config/sample.properties`. From YAML: `kubectl apply -f config/config-map-3.yaml`.

Inject a ConfigMap as environment variables

Look at the Deployment manifest โ€” it pulls two env vars from the two ConfigMaps you just created:

cat config/configmap-demo.yaml
env:
- name: GREETING
  valueFrom:
    configMapKeyRef:
      name: sample
      key: message
- name: MESSAGE
  valueFrom:
    configMapKeyRef:
      name: sample3
      key: message

Apply it:

kubectl apply -f config/configmap-demo.yaml

Wait for the pod:

kubectl wait --for=condition=Available deployment/configmap-demo --timeout=60s

Look at the env inside the container:

kubectl exec deploy/configmap-demo -- printenv | grep -E '^(GREETING|MESSAGE)='

Output:

GREETING=hello
MESSAGE=Cloud AI Campus says hi

Env vars are read at container start. Updating the ConfigMap doesn't update env vars โ€” you need to restart the pod. For live updates, use the volume mount instead (next step).

Click Verify step.

Hint

`kubectl apply -f config/configmap-demo.yaml`, then `kubectl exec deploy/configmap-demo -- printenv` should show GREETING and MESSAGE.

Mount a ConfigMap as a volume

The same Deployment also mounts ConfigMap sample3 as a volume at /etc/config. Each key in the ConfigMap becomes a file with the key's value as its content.

List the mounted files:

kubectl exec deploy/configmap-demo -- ls -la /etc/config

You should see three files: message, retries, feature.banner.

Read one:

kubectl exec deploy/configmap-demo -- cat /etc/config/message
Cloud AI Campus says hi

Why volumes vs env vars? Volumes update live. Edit the ConfigMap:

kubectl patch configmap sample3 --type merge -p '{"data":{"message":"updated"}}'

Re-read the file inside the pod โ€” it may take 10-60 seconds for the kubelet to refresh the projected files:

for i in 1 2 3 4 5 6; do
    kubectl exec deploy/configmap-demo -- cat /etc/config/message
    sleep 10
done

Eventually the file shows updated. Env vars wouldn't.

Click Verify step when /etc/config/message reads updated.

Hint

The same Deployment mounts `sample3` at `/etc/config`. `kubectl exec deploy/configmap-demo -- ls /etc/config`.

Create a Secret

ConfigMaps are perfect for non-sensitive config. For credentials, keys, certificates โ€” anything you wouldn't want printed in plain text โ€” use a Secret.

The two object kinds behave almost identically (env vars + volume mounts), but Secrets:

  • are base64-encoded at rest (not encrypted by default โ€” see the warning at the end).
  • can be marked as encrypted at rest by configuring the API server's encryption provider.
  • are kept in tmpfs when mounted as volumes, never written to disk on the node.

Create a generic Secret from a literal:

kubectl create secret generic db-creds --from-literal=password='s3cret!'

Inspect โ€” note the value is base64-encoded:

kubectl get secret db-creds -o yaml

Decode it for sanity-checking:

kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d; echo

Base64 is encoding, not encryption. Anyone with read access to the Secret can decode it. Production clusters layer on KMS-backed encryption-at-rest and RBAC to restrict who can read Secrets at all.

Click Verify step when the Secret exists.

Hint

`kubectl create secret generic db-creds --from-literal=password=s3cret!`.

Consume the Secret as an env var

The Deployment manifest in config/secret-demo.yaml pulls db-creds.password into the container as DB_PASSWORD:

cat config/secret-demo.yaml
env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: db-creds
      key: password

Apply:

kubectl apply -f config/secret-demo.yaml
kubectl wait --for=condition=Available deployment/secret-demo --timeout=60s

Verify the env arrived in the container:

kubectl exec deploy/secret-demo -- printenv DB_PASSWORD

You should see s3cret!.

The pod can't tell whether the env came from a Secret or a ConfigMap โ€” they look identical inside the container. But your cluster operators do see the difference: Secrets are audited separately, can be encrypted, and tend to be locked down with tighter RBAC.

One more thing. Look at what the pod is logging โ€” it's a tiny busybox loop that prints the password to stdout:

kubectl logs deploy/secret-demo --tail=3

Lesson: consuming a Secret safely is the app's responsibility. Kubernetes hands you a string; if your app leaks it to logs or returns it in an HTTP response, that's on the app.

Click Verify step.

Hint

`kubectl apply -f config/secret-demo.yaml`, then `kubectl exec deploy/secret-demo -- printenv DB_PASSWORD`.

© 2026 Cloud AI Campus