Lesson 06 Secrets & ConfigMaps
Theme:

Lab Guide: Secrets & ConfigMaps

Three hands-on exercises to practise templating ConfigMaps, Secrets, and the checksum rollout trick.

Prerequisites

A running Kubernetes cluster (minikube, kind, or k3d), Helm 3.12+, and kubectl configured to talk to the cluster.

Exercise 1 — ConfigMap from Values and Files

Create a chart that templates a ConfigMap with entries from values.yaml and loads an external configuration file using .Files.Get.

Step 1

Scaffold a new chart and clean up the default templates:

helm create configdemo
cd configdemo
rm templates/tests -rf
rm templates/hpa.yaml templates/ingress.yaml templates/serviceaccount.yaml

Step 2

Create a files/ directory and add a sample config file:

mkdir files
cat > files/app.conf <<'EOF'
[server]
port = 8080
workers = 4

[logging]
level = info
format = json
EOF

Step 3

Add configuration values to values.yaml:

# values.yaml (add to the bottom)
config:
  env: production
  logLevel: info
  maxConnections: "100"

Step 4

Create the ConfigMap template at templates/configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "configdemo.fullname" . }}-config
  labels:
    {{- include "configdemo.labels" . | nindent 4 }}
data:
  APP_ENV: {{ .Values.config.env | quote }}
  LOG_LEVEL: {{ .Values.config.logLevel | quote }}
  MAX_CONNECTIONS: {{ .Values.config.maxConnections | quote }}
  app.conf: |-
{{ .Files.Get "files/app.conf" | indent 4 }}

Step 5

Render the template locally and verify the output:

helm template configdemo . | grep -A 20 "kind: ConfigMap"

You should see all four data keys rendered correctly, with the file content indented under app.conf.

Step 6

Install the chart and verify the ConfigMap exists in the cluster:

helm install configdemo .
kubectl get configmap configdemo-config -o yaml

Checkpoint

The ConfigMap should contain four keys: APP_ENV, LOG_LEVEL, MAX_CONNECTIONS, and app.conf. The app.conf key should contain the full INI file content.

Exercise 2 — Secrets with b64enc and stringData

Add a Secret to the chart using both data (with b64enc) and stringData fields, then mount it as environment variables in the Deployment.

Step 1

Add secret values to values.yaml:

# values.yaml (add to the bottom)
secrets:
  dbPassword: "s3cret-p@ssw0rd"
  apiKey: "ak_live_abc123def456"

Step 2

Create templates/secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: {{ include "configdemo.fullname" . }}-secret
  labels:
    {{- include "configdemo.labels" . | nindent 4 }}
type: Opaque
data:
  DB_PASSWORD: {{ .Values.secrets.dbPassword | b64enc | quote }}
stringData:
  API_KEY: {{ .Values.secrets.apiKey | quote }}

Step 3

Update templates/deployment.yaml to inject the secrets as environment variables. Add the following to the container spec (inside containers[0]):

          envFrom:
            - secretRef:
                name: {{ include "configdemo.fullname" . }}-secret
            - configMapRef:
                name: {{ include "configdemo.fullname" . }}-config

Step 4

Upgrade the release and verify the secret:

helm upgrade configdemo .
kubectl get secret configdemo-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
# Should output: s3cret-p@ssw0rd

kubectl get secret configdemo-secret -o jsonpath='{.data.API_KEY}' | base64 -d
# Should output: ak_live_abc123def456

Step 5

Confirm the pod has the environment variables:

POD=$(kubectl get pod -l app.kubernetes.io/name=configdemo -o jsonpath='{.items[0].metadata.name}')
kubectl exec $POD -- env | grep -E "DB_PASSWORD|API_KEY|APP_ENV"

Checkpoint

The pod should show DB_PASSWORD, API_KEY, and APP_ENV in its environment. Both secret values should decode correctly.

Exercise 3 — Checksum Annotation for Auto-Rollout

Add checksum annotations to the Deployment so that changes to the ConfigMap or Secret trigger a rolling update automatically.

Step 1

Edit templates/deployment.yaml. In the pod template metadata.annotations section, add:

      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}

Step 2

Upgrade without changing any values and note the current pod name:

helm upgrade configdemo .
kubectl get pods -l app.kubernetes.io/name=configdemo
# Note the pod name and AGE

Step 3

Now change a config value and upgrade again:

helm upgrade configdemo . --set config.logLevel=debug

Step 4

Verify that a new pod was created (rolling update triggered):

kubectl get pods -l app.kubernetes.io/name=configdemo
# The pod name should be different and AGE should be very recent

Step 5

Inspect the annotation to confirm the checksum changed:

kubectl get deployment configdemo -o jsonpath='{.spec.template.metadata.annotations}' | python3 -m json.tool

Checkpoint

Changing config.logLevel should result in a new pod. The checksum/config annotation value should differ between the two upgrades.

Cleanup

helm uninstall configdemo
cd .. && rm -rf configdemo

What you practised

Creating ConfigMaps from values and files, templating Secrets with b64enc and stringData, mounting both as environment variables, and using checksum annotations for automatic rollouts on config changes.