ConfigMap and Secret
Creating, injecting, and mounting ConfigMaps and Secrets
Overview
ConfigMap and Secret are used to decouple configuration data from container images. ConfigMap stores non-sensitive data, while Secret stores sensitive data (Base64 encoded).
1. ConfigMap
1.1 Creating ConfigMaps
kubectl create configmap app-config --from-literal=APP_COLOR=blue --from-literal=APP_MODE=production
# Create from a file (filename becomes the key)
kubectl create configmap app-config --from-file=app.properties
# Create from a file (custom key)
kubectl create configmap app-config --from-file=custom-key=app.properties
# Create from an env-file
kubectl create configmap app-config --from-env-file=app.env
# Create from a directory
kubectl create configmap app-config --from-dir=config/
# Generate YAML
kubectl create configmap app-config --from-literal=APP_COLOR=blue --dry-run=client -o yaml
1.2 ConfigMap YAML Example
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_COLOR: blue
APP_MODE: production
app.properties: |
key1=value1
key2=value2
# View ConfigMaps
kubectl get configmaps
kubectl get cm
kubectl describe cm app-config
kubectl get cm app-config -o yaml
2. Secret
Data in Secrets is stored as Base64 encoding.
2.1 Creating Secrets
# generic: Create from literal values
kubectl create secret generic db-secret \
--from-literal=DB_USER=admin \
--from-literal=DB_PASSWORD=supersecret
# generic: Create from a file
kubectl create secret generic db-secret --from-file=db.env
# tls: Create a TLS certificate Secret
kubectl create secret tls tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key
# docker-registry: Image registry authentication
kubectl create secret docker-registry regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<user> \
--docker-password=<password> \
--docker-email=<email>
# Generate YAML
kubectl create secret generic db-secret --from-literal=DB_PASSWORD=pass123 --dry-run=client -o yaml
2.2 Secret YAML Example
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
DB_USER: YWRtaW4= # base64 encoded
DB_PASSWORD: c3VwZXJzZWNyZXQ=
2.3 Base64 Encoding and Decoding
# Encode
echo -n "admin" | base64
echo -n "supersecret" | base64
# Decode
echo "YWRtaW4=" | base64 -d
echo "c3VwZXJzZWNyZXQ=" | base64 -d
# Use stringData in Secret YAML directly (plain text, K8s auto-encodes)
# Using stringData (stored as plain text, auto-converted to data on creation)
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
DB_USER: admin
DB_PASSWORD: supersecret
3. Injecting into Pod Environment Variables
3.1 Using env (Individual Injection)
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: app
image: nginx
env:
- name: APP_COLOR # Environment variable name in the container
valueFrom:
configMapKeyRef:
name: app-config # ConfigMap name
key: APP_COLOR # Key in the ConfigMap
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORD
3.2 Using envFrom (Batch Injection)
apiVersion: v1
kind: Pod
metadata:
name: envfrom-pod
spec:
containers:
- name: app
image: nginx
envFrom:
- configMapRef:
name: app-config # Inject all ConfigMap entries
optional: true # Don't error if ConfigMap doesn't exist
- secretRef:
name: db-secret # Inject all Secret entries
3.3 Prefix Handling
envFrom:
- configMapRef:
name: app-config
prefix: CONFIG_ # Add CONFIG_ prefix to all variable names
4. Mounting as Volumes
4.1 ConfigMap Mounted as a Volume
apiVersion: v1
kind: Pod
metadata:
name: configmap-volume
spec:
volumes:
- name: config-volume
configMap:
name: app-config
items: # Optional: only mount specific keys
- key: app.properties
path: myapp.properties # Filename after mounting
containers:
- name: app
image: nginx
volumeMounts:
- name: config-volume
mountPath: /etc/config
4.2 Secret Mounted as a Volume
apiVersion: v1
kind: Pod
metadata:
name: secret-volume
spec:
volumes:
- name: secret-volume
secret:
secretName: db-secret
defaultMode: 0400 # File permissions (default is 0644)
containers:
- name: app
image: nginx
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
# Inspect the mounted Secret (each key becomes a file)
kubectl exec secret-volume -- ls /etc/secret
kubectl exec secret-volume -- cat /etc/secret/DB_PASSWORD
# Note: Secrets mounted as volumes are automatically decoded to plain text
4.3 Hot Reload (Automatic Updates)
When ConfigMap/Secret is mounted as a volume, updating the ConfigMap/Secret will automatically update the files in the Pod (with a delay of seconds to minutes).
# Update ConfigMap
kubectl edit cm app-config
# Verify the file in the volume has been updated
kubectl exec configmap-volume -- cat /etc/config/APP_COLOR
Note: Environment variables injected via env/envFrom are not hot-reloaded; a Pod restart is required.
5. Immutable ConfigMap/Secret
Kubernetes 1.21+ supports immutable ConfigMaps/Secrets, improving performance and preventing accidental modification.
apiVersion: v1
kind: ConfigMap
metadata:
name: immutable-config
data:
APP_COLOR: blue
immutable: true
apiVersion: v1
kind: Secret
metadata:
name: immutable-secret
type: Opaque
stringData:
DB_PASSWORD: supersecret
immutable: true
# Once set to immutable, you must delete and recreate to modify
kubectl delete cm immutable-config
kubectl create cm immutable-config --from-literal=APP_COLOR=red
6. Practical Exam Commands
# Quickly create and inject a ConfigMap
kubectl create configmap app-env --from-literal=DEBUG=true --from-literal=LOG_LEVEL=info
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml
# Add envFrom in pod.yaml
# Create a Secret and use it in a Pod
kubectl create secret generic my-secret --from-literal=SECRET_KEY=abc123
kubectl run secret-pod --image=busybox --dry-run=client -o yaml -- sleep 3600 > secret-pod.yaml
# Add env/volume referencing the Secret
# Check Secret contents
kubectl get secret my-secret -o jsonpath='{.data.SECRET_KEY}' | base64 -d
# Inject all keys from a ConfigMap/Secret as environment variables
kubectl create configmap full-config --from-env-file=./app.env
kubectl run app --image=nginx --restart=Never -o yaml --dry-run=client > app.yaml
# Edit to add envFrom.configMapRef
# Load from Secret and verify
kubectl create secret generic creds --from-literal=user=admin --from-literal=pass=secret123
kubectl run secret-test --image=busybox --restart=Never -it --rm -- env | grep user
🧪 Complete Hands-on Example: Create ConfigMap and Secret and Inject into a Pod
Scenario Description
Create an application configuration ConfigMap and a database password Secret, then inject them into a Pod via both environment variables and volume mounts.
Prerequisites
- A working Kubernetes cluster
- kubectl configured to connect to the cluster
Steps
Step 1: Create ConfigMap and Secret
# Create ConfigMap (application configuration)
kubectl create configmap app-config \
--from-literal=APP_COLOR=blue \
--from-literal=APP_MODE=production \
--from-literal=LOG_LEVEL=info
# Expected output: configmap/app-config created
# Create Secret (database credentials)
kubectl create secret generic db-secret \
--from-literal=DB_USER=admin \
--from-literal=DB_PASSWORD=Sup3rS3cret!
# Expected output: secret/db-secret created
# View creation results
kubectl get cm app-config -o yaml | head -10
kubectl get secret db-secret -o yaml | head -10
Step 2: Inject via environment variables into a Pod
cat <<'EOF' > pod-env-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-env-demo
spec:
containers:
- name: app
image: busybox:1.28
command: ["sleep", "3600"]
env:
- name: APP_COLOR
valueFrom:
configMapKeyRef:
name: app-config
key: APP_COLOR
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORD
EOF
kubectl apply -f pod-env-demo.yaml
# Expected output: pod/pod-env-demo created
Step 3: Inject via volume mount into a Pod
cat <<'EOF' > pod-volume-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-demo
spec:
volumes:
- name: config-volume
configMap:
name: app-config
- name: secret-volume
secret:
secretName: db-secret
containers:
- name: app
image: busybox:1.28
command: ["sleep", "3600"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: secret-volume
mountPath: /etc/secret
EOF
kubectl apply -f pod-volume-demo.yaml
# Expected output: pod/pod-volume-demo created
Verification Results
# Verify environment variable injection
kubectl exec pod-env-demo -- env | grep -E "APP_COLOR|DB_USER|DB_PASSWORD"
# Expected output:
# APP_COLOR=blue
# DB_USER=admin
# DB_PASSWORD=Sup3rS3cret!
# Verify volume mount injection
kubectl exec pod-volume-demo -- ls /etc/config
# Expected output: APP_COLOR APP_MODE LOG_LEVEL
kubectl exec pod-volume-demo -- cat /etc/secret/DB_PASSWORD
# Expected output: Sup3rS3cret! (Secret auto-decoded to plain text when mounted as a volume)
# Cleanup
kubectl delete pod pod-env-demo pod-volume-demo
kubectl delete cm app-config
kubectl delete secret db-secret
# Expected output: pod "pod-env-demo" deleted
# pod "pod-volume-demo" deleted
# configmap "app-config" deleted
# secret "db-secret" deleted
Exam Tips
- Values in Secrets are Base64 encoded, not encrypted. Sensitive data should use external key management tools (such as Vault) or enable KMS encryption
envFromcan inject all entries from a ConfigMap/Secret in bulk, saving YAML space, but you cannot select specific keys- Volume mount method supports hot reload (files in Pod update automatically when ConfigMap/Secret is modified), but
envinjection does not - When mounted as a volume, Secret files default to 0644 permissions; use
defaultModeto change to 0400 - In the exam, commonly use
kubectl exec <pod> -- env | grep <key>to quickly verify injection success