TT Lab
Get started
Learn Learning paths Courses

CKAD — Kubernetes Application Developer

Injecting Configuration With ConfigMaps and Secrets

Continue in TT Lab

Goal

You tell apart and use four injection paths (all environment variables, individual environment variables, a file volume, a subPath file) that make the same image behave differently in each environment, and handle the differences between a Secret and a ConfigMap at the field level.

Why it matters

The point where configuration injection causes real-world incidents is mostly "is the update reflected?" A value injected as an environment variable is read once when the process starts and that is it, so even if you edit the ConfigMap, it never changes until you recreate the Pod. A file injected as a volume is refreshed periodically by the kubelet, but a file mounted with subPath is the exception and is not refreshed. If you do not know these three behavioral differences, you spend all your time on "I changed the configuration, so why is it not taking effect?"

defaultMode also trips people up often in practice. When you mount a Secret, the default permission is 0644, so other processes on the same node can read it. Narrow sensitive files such as a TLS key to 0400. In YAML, 0400 without quotes is interpreted as octal, but writing just 400 is read as decimal 400, giving an unintended permission.

immutable: true is a performance feature, not a security feature. The kubelet keeps hitting the API server to watch mounted ConfigMaps/Secrets for changes, and when they are immutable it stops watching. At the scale of thousands of Pods, apiserver load drops noticeably.

Steps

  1. Create the namespace ckad-config, and in it create the ConfigMap app-config from literals. The keys are APP_MODE=production and LOG_LEVEL=info.
  2. Create the directory /root/ckad-config, write the single line timeout=30 to the file /root/ckad-config/app.properties, and then create the ConfigMap app-props from that file (the key name is app.properties).
  3. Create a Pod cfg-env. Image busybox:1.36, command: ["/bin/sh","-c","sleep 3600"]. Inject all of app-config with envFrom, and in addition reference the LOG_LEVEL key of app-config in env under the name LOG.
  4. Create the Secret db-secret. The type is generic (Opaque), and the keys are DB_USER=appuser and DB_PASSWORD=s3cr3t.
  5. Create a Pod secret-consumer. Image busybox:1.36, command: ["/bin/sh","-c","sleep 3600"]. Take the environment variable DB_PASSWORD from the DB_PASSWORD key of db-secret, and also mount the same Secret as the volume dbcreds at /etc/db with defaultMode set to 0400.
  6. Create a Pod cfg-vol. Image nginx:1.27. Mount the ConfigMap app-props twice as the volume props — once as a whole directory at /etc/app, and once with subPath: app.properties at /opt/app/app.properties.
  7. Create the ConfigMap feature-flags. Key NEW_UI=on, and immutable: true. Create a Pod optional-cm (image busybox:1.36, command: ["/bin/sh","-c","sleep 3600"]) that references the nonexistent ConfigMap maybe-config through envFrom with optional: true.
  8. Create a Deployment web-config. 2 replicas, label app=web-config, image nginx:1.27. Put both app-config (configMapRef) and db-secret (secretRef) in envFrom, and mount the ConfigMap app-props as the volume props at /etc/app.

Notes

Creating a ConfigMap from literals

Create the namespace ckad-config, and in it create the ConfigMap app-config from literals. The keys are APP_MODE=production and LOG_LEVEL=info.

You can give kubectl create configmap several --from-literal=키=값 flags (the placeholders are the key and the value). Create the namespace first and do not forget -n.

Creating a ConfigMap from a file

Create the directory /root/ckad-config, write the single line timeout=30 to the file /root/ckad-config/app.properties, and then create the ConfigMap app-props from that file (the key name is app.properties).

With --from-file=경로 (the placeholder is the file path), the file name becomes the key and the entire file content becomes the value. To change the key name, use the --from-file=키이름=경로 form (the placeholders are the key name and the file path).

Using envFrom and configMapKeyRef together

Create a Pod cfg-env. Image busybox:1.36, command: ["/bin/sh","-c","sleep 3600"]. Inject all of app-config with envFrom, and in addition reference the LOG_LEVEL key of app-config in env under the name LOG.

envFrom[].configMapRef turns every key into a variable name as is, and env[].valueFrom.configMapKeyRef picks one key and injects it under a different name. You can use both approaches in one container.

Creating a Secret and checking the encoding

Create the Secret db-secret. The type is generic (Opaque), and the keys are DB_USER=appuser and DB_PASSWORD=s3cr3t.

The --from-literal values of kubectl create secret generic are base64-encoded automatically. When writing YAML directly and you want to put in plaintext, use stringData instead of data.

Injecting a Secret as both an environment variable and a file

Create a Pod secret-consumer. Image busybox:1.36, command: ["/bin/sh","-c","sleep 3600"]. Take the environment variable DB_PASSWORD from the DB_PASSWORD key of db-secret, and also mount the same Secret as the volume dbcreds at /etc/db with defaultMode set to 0400.

For an environment variable use env[].valueFrom.secretKeyRef; for a file use volumes[].secret.secretName and a volume mount. Set the file permission with defaultMode on the volume side, and be careful, since in YAML it is easy to drop the leading 0 of an octal value.

ConfigMap volume and subPath

Create a Pod cfg-vol. Image nginx:1.27. Mount the ConfigMap app-props twice as the volume props — once as a whole directory at /etc/app, and once with subPath: app.properties at /opt/app/app.properties.

If you mount over a whole directory, the directory's original contents are hidden. To lay down just one file, write the key name in volumeMounts[].subPath. A file mounted with subPath is not updated even if you modify the ConfigMap.

optional references and an immutable ConfigMap

Create the ConfigMap feature-flags. Key NEW_UI=on, and immutable: true. Create a Pod optional-cm (image busybox:1.36, command: ["/bin/sh","-c","sleep 3600"]) that references the nonexistent ConfigMap maybe-config through envFrom with optional: true.

immutable: true is a top-level field of the ConfigMap spec (not inside the data). To let the Pod start even when it references a nonexistent ConfigMap, give the referencing side optional: true.

All three at once in a Deployment (comprehensive)

Create a Deployment web-config. 2 replicas, label app=web-config, image nginx:1.27. Put both app-config (configMapRef) and db-secret (secretRef) in envFrom, and mount the ConfigMap app-props as the volume props at /etc/app.

Use the two ConfigMaps and one Secret you made earlier in a single Deployment. In the envFrom array you can put configMapRef and secretRef side by side. Do not forget the volume mount either.