Managing your app configurations and secrets securely is non-negotiable in modern cloud-native development. Kubernetes offers two native resources to do this:
- π ConfigMaps for non-sensitive configuration
- π Secrets for credentials, tokens, and other sensitive values
In this guide, weβll show how to use both in a real-world Node.js app deployed to Kubernetes.
β¨ What You'll Learn
β
Difference between ConfigMaps and Secrets
β
Creating secure configurations using YAML
β
Deploying a Node.js app with injected env vars
β
Debugging and accessing environment inside the container
β
Docker + Kubernetes best practices for configuration
π¦ Demo Image & Source Code
We're using a public Docker image that reads environment variables and returns them:
- π¦ Docker:
zaheetdeveloper/k8s-config-demo - π§ͺ Code + YAMLs: GitHub Repo
π Project Structure
k8s-config-demo/ βββ index.js βββ Dockerfile βββ configmap.yaml βββ secret.yaml βββ deployment.yaml π§ Why ConfigMaps & Secrets?
ConfigMap
- Stores non-sensitive values like
APP_MODE, URLs, etc.
Secret
- Stores sensitive data like
DB_USER,DB_PASSWORD - Encoded in Base64 and supports encryption at rest
Using them ensures:
- π You donβt hardcode values
- π You can change config without rebuilding the image
- π§© They integrate cleanly into deployments
π§° The Application Code (index.js)
const http = require('http'); const PORT = process.env.PORT || 3000; const DB_USER = process.env.DB_USER; const DB_PASSWORD = process.env.DB_PASSWORD; const APP_MODE = process.env.APP_MODE || 'dev'; http.createServer((req, res) => { res.end(`Mode: ${APP_MODE}, DB_USER: ${DB_USER}`); }).listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); π³ Dockerfile
FROM node:alpine WORKDIR /app COPY index.js . CMD ["node", "index.js"] Build and push (already done):
docker build -t zaheetdeveloper/k8s-config-demo:v1 . docker push zaheetdeveloper/k8s-config-demo:v1 π§ Step-by-Step Kubernetes Setup
1οΈβ£ Create the ConfigMap
apiVersion: v1 kind: ConfigMap metadata: name: app-config data: APP_MODE: production kubectl apply -f configmap.yaml 2οΈβ£ Create the Secret
apiVersion: v1 kind: Secret metadata: name: db-secret type: Opaque data: DB_USER: YWRtaW4= # 'admin' DB_PASSWORD: c2VjdXJl # 'secure' kubectl apply -f secret.yaml 3οΈβ£ Create the Deployment
apiVersion: apps/v1 kind: Deployment metadata: name: app-config-test spec: replicas: 1 selector: matchLabels: app: config-app template: metadata: labels: app: config-app spec: automountServiceAccountToken: false containers: - name: app-container image: zaheetdeveloper/k8s-config-demo:v1 env: - name: APP_MODE valueFrom: configMapKeyRef: name: app-config key: APP_MODE - name: DB_USER valueFrom: secretKeyRef: name: db-secret key: DB_USER - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: DB_PASSWORD ports: - containerPort: 3000 resources: requests: cpu: "100m" memory: "128Mi" ephemeral-storage: "128Mi" limits: cpu: "500m" memory: "512Mi" ephemeral-storage: "512Mi" kubectl apply -f deployment.yaml π§ͺ Testing & Debugging
kubectl get pods kubectl logs -l app=config-app Expected output:
Server running on port 3000 kubectl port-forward deployment/app-config-test 3000:3000 Visit in browser: http://localhost:3000

kubectl exec -it pod/<pod-name> -- /bin/sh env π‘οΈ Best Practices
- Encrypt secrets at rest using KMS
- Avoid storing secrets in source code
- Use RBAC to control access
- Explore tools like Sealed Secrets or External Secrets Operator
π¬ Conclusion
You now know how to:
- Use ConfigMaps and Secrets in Kubernetes
- Inject them securely into containers
- Deploy and inspect a working environment
β‘οΈ Demo image: Docker Hub
π Source code & YAMLs: GitHub




Top comments (0)