Kubernetes ConfigMap & Secret Hands‐on Lab - neerajk555/Kubernetes GitHub Wiki

This lab will cover:

  1. ConfigMap – creation, usage, update, and cleanup
  2. Secret – creation, usage, update, and cleanup
  3. Best practices and verification commands

Prerequisites

  • A running Kubernetes cluster (Minikube, Kind, or Cloud cluster).
  • kubectl installed and configured.
  • Basic knowledge of Pods.

1. ConfigMap Hands-on

A ConfigMap stores non-sensitive configuration data in key-value format.


Step 1: Create a ConfigMap

We will create a ConfigMap in three ways.


1A. From Literal Values

kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --from-literal=APP_PORT=8080

Explanation:

  • kubectl create configmap → Creates a new ConfigMap.
  • --from-literal → Directly define key-value pairs.
  • app-config → Name of the ConfigMap.

Verify:

kubectl get configmap app-config -o yaml

You should see:

data:
  APP_ENV: production
  APP_PORT: "8080"

1B. From File

  1. Create a file app.properties:
echo "APP_ENV=staging" > app.properties
echo "APP_PORT=9090" >> app.properties
  1. Create ConfigMap from file:
kubectl create configmap app-config-file --from-file=app.properties
  1. Verify:
kubectl describe configmap app-config-file

Explanation:
Each line in the file is stored as the file’s content under the file name as the key.


1C. From YAML Manifest

app-config.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-yaml
data:
  APP_ENV: "dev"
  APP_PORT: "3000"
  FEATURE_FLAG: "true"

Apply:

kubectl apply -f app-config.yaml

Verify:

kubectl get configmap app-config-yaml -o yaml

Step 2: Use ConfigMap in a Pod

We can inject ConfigMap data as environment variables or files.


2A. As Environment Variables

configmap-env-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: configmap-env-pod
spec:
  containers:
  - name: demo-container
    image: busybox
    command: ["sh", "-c", "env; sleep 3600"]
    envFrom:
    - configMapRef:
        name: app-config

Explanation:

  • envFrom loads all keys from the ConfigMap as environment variables.
  • busybox prints the environment variables and sleeps.

Deploy:

kubectl apply -f configmap-env-pod.yaml
kubectl logs configmap-env-pod

You will see:

APP_ENV=production
APP_PORT=8080

2B. As Files in a Volume

configmap-volume-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: configmap-volume-pod
spec:
  containers:
  - name: demo-container
    image: busybox
    command: ["sh", "-c", "ls /etc/config; cat /etc/config/*; sleep 3600"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

Explanation:

  • Mounts each ConfigMap key as a separate file in /etc/config.
  • File name = key, content = value.

Deploy and check logs:

kubectl apply -f configmap-volume-pod.yaml
kubectl logs configmap-volume-pod

Step 3: Update ConfigMap

kubectl edit configmap app-config
# Change APP_PORT: "8081"
  • If mounted as Volume → Files update automatically.
  • If used as Env Vars → Pod must be restarted:
kubectl delete pod configmap-env-pod
kubectl apply -f configmap-env-pod.yaml

Step 4: Cleanup ConfigMap Resources

kubectl delete pod configmap-env-pod configmap-volume-pod
kubectl delete configmap app-config app-config-file app-config-yaml

2. Secret Hands-on

A Secret stores sensitive data like passwords or API keys.


Step 1: Create a Secret


1A. From Literal Values

kubectl create secret generic db-secret \
  --from-literal=DB_USER=admin \
  --from-literal=DB_PASS=MyP@ss123

Verify:

kubectl get secret db-secret -o yaml

Values will appear base64-encoded.

Decode to check:

kubectl get secret db-secret -o jsonpath='{.data.DB_USER}' | base64 --decode

1B. From File

echo -n "admin" > username.txt
echo -n "MyP@ss123" > password.txt

kubectl create secret generic db-secret-file \
  --from-file=username.txt \
  --from-file=password.txt

Explanation:

  • Each file name = key, content = value (base64-encoded).

1C. From YAML Manifest

Encode values:

echo -n "admin" | base64   # YWRtaW4=
echo -n "MyP@ss123" | base64  # TXlQQHNzMTIz

db-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: db-secret-yaml
type: Opaque
data:
  DB_USER: YWRtaW4=
  DB_PASS: TXlQQHNzMTIz

Apply:

kubectl apply -f db-secret.yaml

Step 2: Use Secret in a Pod


2A. As Environment Variables

secret-env-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
  - name: demo-container
    image: busybox
    command: ["sh", "-c", "env; sleep 3600"]
    envFrom:
    - secretRef:
        name: db-secret

Check logs:

kubectl logs secret-env-pod

2B. As Files in a Volume

secret-volume-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: secret-volume-pod
spec:
  containers:
  - name: demo-container
    image: busybox
    command: ["sh", "-c", "ls /etc/secret; cat /etc/secret/*; sleep 3600"]
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
  volumes:
  - name: secret-volume
    secret:
      secretName: db-secret

Step 3: Update Secret

kubectl create secret generic db-secret \
  --from-literal=DB_USER=admin \
  --from-literal=DB_PASS=NewP@ss456 \
  --dry-run=client -o yaml | kubectl apply -f -

Mounted as volumes → auto-update
Used as env vars → restart Pod


Step 4: Cleanup Secret Resources

kubectl delete pod secret-env-pod secret-volume-pod
kubectl delete secret db-secret db-secret-file db-secret-yaml

3. Best Practices

  1. Never commit secrets in Git → Use an external secret manager.
  2. Use encryption at rest for etcd for secrets.
  3. Use RBAC to restrict secret access.
  4. Prefer volume mounts for dynamic updates.
  5. Use immutable ConfigMaps/Secrets for rarely changed configs.