Externalize Configuration
Move environment-specific content out of the image with a chart-managed ConfigMap and mounted file.
An image should mean the same thing in development and production. Configuration answers a different question: how should that image behave in this environment?
Download this chapter's files
Use your browser to download either ivia-chapter-06.tar.gz or ivia-chapter-06.zip. The archive is self-contained; you do not need this tutorial repository.
Open a terminal after the browser download:
cd ~/Downloads
tar -xzf ivia-chapter-06.tar.gz
cd ivia-chapter-06
All remaining relative paths in this chapter start from that extracted directory.
The challenge
Challenge: change the static page's environment banner through a ConfigMap without rebuilding simple-static:local.
Prerequisites
- A running Minikube cluster with the extracted static source.
- Helm and kubectl.
- Permission to create a
workdirectory in the extracted package.
Learning goals
- Distinguish build-time assets from runtime configuration
- Create a ConfigMap through chart values
- Mount one ConfigMap key as one nginx file
- Explain why secrets do not belong in ConfigMaps
Prepare the standalone exercise
Build the packaged source into Minikube and prepare the chart's scheduling label:
minikube image build -t simple-static:local static-app
kubectl label node minikube ivia.ch/nodetype=app --overwrite
kubectl create namespace tutorial \
--dry-run=client -o yaml \
| kubectl apply -f -
Create configuration values
mkdir -p work
cat > work/simple-app-config.yaml <<'EOF'
components:
frontend:
enabled: true
name: frontend
image: {repository: simple-static, tag: local, pullPolicy: IfNotPresent}
port: 8080
health: /healthz
readinessProbe: |
httpGet:
path: {{ .Component.health }}
port: {{ include "ivia.firstPort" . }}
periodSeconds: 5
livenessProbe: |
httpGet:
path: {{ .Component.health }}
port: {{ include "ivia.firstPort" . }}
periodSeconds: 10
configMaps:
- name: page
data:
environment.txt: "Hello from Minikube configuration!"
configMapVolumes:
- name: page-config
configMapName: '{{ include "ivia.componentName" . }}-page'
mountPath: /usr/share/nginx/html/environment.txt
subPath: environment.txt
readOnly: true
ingress:
enabled: false
backend:
enabled: false
EOF
Render and inspect before applying:
helm template simple-app \
oci://harbor.ivia.ch/ivia-generic-helm-chart/ivia-generic-helm-chart \
--version 4.8.0 -n tutorial -f work/simple-app-config.yaml \
| grep -E 'kind: ConfigMap|mountPath:|environment.txt'
Apply and validate
helm upgrade --install simple-app \
oci://harbor.ivia.ch/ivia-generic-helm-chart/ivia-generic-helm-chart \
--version 4.8.0 -n tutorial --atomic --timeout 5m \
-f work/simple-app-config.yaml
kubectl rollout status deployment/simple-app-frontend -n tutorial --timeout=120s
kubectl port-forward service/simple-app-frontend 8080:8080 -n tutorial
In a second terminal:
curl --fail http://localhost:8080/environment.txt
kubectl get configmap simple-app-frontend-page -n tutorial -o yaml
Change only the text in the temporary values file, repeat helm upgrade, and curl again. A fresh Pod mounts the current ConfigMap. Use extraEnv for scalar process settings, mounted ConfigMaps for files, and Secrets or an external secret manager for credentials.
Expected validation
Curl prints Hello from Minikube configuration!. The image remains simple-static:local; only release configuration and the Pod revision change.
Troubleshooting and common pitfalls
- Mounted path becomes a directory: include
subPathwhen mounting one key as one file. - ConfigMap not found: chart names include release and component prefixes; preserve the templated name exactly.
- Old content remains: wait for rollout completion. Kubernetes does not update a
subPathmount in place. - YAML template breaks: preserve single quotes around
configMapName. - Credentials in ConfigMap: ConfigMaps are not secret. Never commit real passwords or tokens.
- Editing ConfigMap directly: the next Helm upgrade restores values; make values the source of truth.
Separating configuration from images makes promotion between environments predictable. You are building a strong operational habit.