Day 7: ConfigMaps and Secrets
What You'll Learn Today
- Managing configuration data with ConfigMaps
- Managing sensitive data with Secrets
- Using environment variables and volume mounts
- Migrating from Docker Compose .env files
Why Separate Configuration?
In the Docker book, you managed settings with environment variables, docker-compose.yml environment sections, and .env files. Kubernetes handles this more systematically with ConfigMaps and Secrets.
flowchart TB
subgraph Docker["Docker Compose"]
ENV[".env file"]
DENV["environment:\n DB_HOST: db"]
end
subgraph K8s["Kubernetes"]
CM["ConfigMap\n(general settings)"]
SEC["Secret\n(sensitive data)"]
end
ENV -->|"migrate"| CM
ENV -->|"sensitive data"| SEC
DENV -->|"migrate"| CM
style Docker fill:#f59e0b,color:#fff
style K8s fill:#3b82f6,color:#fff
| Docker | Kubernetes | Purpose |
|---|---|---|
| environment: | ConfigMap | General configuration values |
| .env file | ConfigMap / Secret | Settings and sensitive data |
| docker secret | Secret | Passwords, API keys, etc. |
ConfigMap
A ConfigMap stores non-sensitive configuration data as key-value pairs.
Creating ConfigMaps
1. From YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
APP_PORT: "3000"
LOG_LEVEL: "info"
DATABASE_HOST: "postgres-service"
2. From the command line
# From literal values
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=APP_PORT=3000
# From a file
kubectl create configmap nginx-config \
--from-file=nginx.conf
# From a directory
kubectl create configmap configs \
--from-file=./config-dir/
3. Storing entire config files
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Using ConfigMaps
As environment variables
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: nginx:1.27
envFrom:
- configMapRef:
name: app-config
# Or individually
env:
- name: MY_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
As a volume mount
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: web
image: nginx:1.27
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: nginx-config
Volume-mounted ConfigMaps auto-update in the Pod (with a few minutes delay). Environment variables require a Pod restart.
Secret
A Secret stores sensitive data such as passwords, tokens, and keys.
ConfigMap vs. Secret
| Aspect | ConfigMap | Secret |
|---|---|---|
| Purpose | General configuration | Sensitive data |
| Data format | Plain text | Base64 encoded |
| Size limit | 1MiB | 1MiB |
| Storage | Disk | tmpfs (memory) |
Creating Secrets
1. From YAML
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: YWRtaW4= # echo -n "admin" | base64
password: c2VjcmV0MTIz # echo -n "secret123" | base64
2. Using stringData (no Base64 needed)
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
username: admin
password: secret123
3. From the command line
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password=secret123
Using Secrets
As environment variables
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
As a volume mount
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app:1.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-secret
Secret Types
| Type | Purpose |
|---|---|
Opaque |
Generic sensitive data (default) |
kubernetes.io/dockerconfigjson |
Docker registry credentials |
kubernetes.io/tls |
TLS certificate and private key |
kubernetes.io/basic-auth |
Basic authentication credentials |
Practical Example: Complete Configuration
Migrating a Docker Compose .env and environment configuration to Kubernetes.
Docker Compose (Source)
services:
web:
image: my-web-app:1.0
environment:
- APP_ENV=production
- DB_HOST=db
- DB_PORT=5432
- DB_NAME=myapp
- DB_USER=admin
- DB_PASSWORD=secret123
Kubernetes (Target)
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
DB_HOST: "postgres-service"
DB_PORT: "5432"
DB_NAME: "myapp"
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
DB_USER: admin
DB_PASSWORD: secret123
---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: my-web-app:1.0
ports:
- containerPort: 3000
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
flowchart TB
CM["ConfigMap\napp-config"] -->|"envFrom"| POD["Pod"]
SEC["Secret\napp-secret"] -->|"envFrom"| POD
POD -->|"DB_HOST=postgres-service"| DB["PostgreSQL\nService"]
style CM fill:#3b82f6,color:#fff
style SEC fill:#ef4444,color:#fff
style POD fill:#22c55e,color:#fff
Managing ConfigMaps and Secrets
# ConfigMap operations
kubectl get configmaps
kubectl describe configmap app-config
kubectl get configmap app-config -o yaml
# Secret operations
kubectl get secrets
kubectl describe secret app-secret
# Decode a Secret value
kubectl get secret app-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 --decode
# Update
kubectl edit configmap app-config
kubectl edit secret app-secret
Secret Security Considerations
Important: Kubernetes Secrets are only Base64 encoded by default β they are NOT encrypted.
For production, consider these measures:
| Measure | Description |
|---|---|
| etcd encryption | Encrypt Secret data stored in etcd |
| RBAC | Control Secret access with role-based access control |
| External secret managers | Integrate with AWS Secrets Manager, HashiCorp Vault, etc. |
| Keep Secrets out of Git | Never commit Secret YAMLs to version control |
Summary
| Concept | Description |
|---|---|
| ConfigMap | Manages general config data as key-value pairs |
| Secret | Manages sensitive data with Base64 encoding |
| envFrom | Bulk inject ConfigMap/Secret as environment variables |
| Volume Mount | Mount config files into Pods |
| stringData | Write Secrets without Base64 encoding |
Key Takeaways
- Separate configuration into ConfigMaps (general) and Secrets (sensitive)
- Use
envFromfor bulk injection,valueFromfor individual keys - Secrets are Base64 encoded, not encrypted β additional security measures are needed in production
Practice Exercises
Exercise 1: Basics
Split these settings into ConfigMap and Secret:
- APP_NAME: "MyApp" (ConfigMap)
- LOG_LEVEL: "debug" (ConfigMap)
- API_KEY: "abc123xyz" (Secret)
- JWT_SECRET: "my-jwt-secret" (Secret)
Exercise 2: File Mount
Store an Nginx configuration file (nginx.conf) in a ConfigMap and mount it into a Pod as a volume.
Challenge
Experiment with updating a ConfigMap and observe how changes propagate to existing Pods. Compare behavior between environment variable injection and volume mounts.
References
Next up: In Day 8, you'll learn about "Ingress and External Access" β more flexible HTTP routing than NodePort or LoadBalancer.