📝 Kubernetes

ConfigMap and Secret: Configuration in Kubernetes

P
Author
Pyland
📅
Published
30.06.2026
⏱️
Reading time
2 min
👁️
Views
89
🌳
Level
Advanced

Configuration must not be baked into a Docker image. Different environments (dev, staging, production) require different values. K8s solves this with ConfigMap and Secret.

Why Config Must Not Live in the Image

When you hardcode config into an image:

  • You have to rebuild the image for every environment
  • Secrets end up in the image layer history
  • There is no way to update the config without a rebuild

Rule: an image is an immutable artifact. Config and secrets are external dependencies that get mounted at runtime.

ConfigMap: Non-Secret Data

ConfigMap stores non-sensitive settings: service URLs, database names, application parameters.

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: postgres-service
  DATABASE_PORT: "5432"
  DATABASE_NAME: myapp
  LOG_LEVEL: info
  APP_ENV: production
# Apply
kubectl apply -f configmap.yaml

# Create imperatively
kubectl create configmap app-config \
  --from-literal=DATABASE_HOST=postgres-service \
  --from-literal=LOG_LEVEL=info

# Create from a file
kubectl create configmap nginx-config --from-file=nginx.conf

# Inspect
kubectl get configmap app-config -o yaml
kubectl describe configmap app-config

Secret: Sensitive Data

Secret stores sensitive data: passwords, API keys, tokens. Values are stored as base64 (this is encoding, not encryption — solely for JSON/YAML compatibility).

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DATABASE_PASSWORD: cGFzc3dvcmQxMjM=   # base64("password123")
  API_KEY: c2VjcmV0LWFwaS1rZXk=         # base64("secret-api-key")
  JWT_SECRET: bXlzdXBlcnNlY3JldA==      # base64("mysupersecret")
# Encode to base64
echo -n "password123" | base64
# cGFzc3dvcmQxMjM=

# Decode
echo "cGFzc3dvcmQxMjM=" | base64 -d
# password123

# Create a Secret imperatively (safer — does not leave values in shell history)
kubectl create secret generic app-secrets \
  --from-literal=DATABASE_PASSWORD=password123 \
  --from-literal=API_KEY=secret-api-key

# Inspect (values are redacted)
kubectl get secret app-secrets -o yaml
# data:
#   DATABASE_PASSWORD: cGFzc3dvcmQxMjM=

Special Secret types:

# TLS certificate
kubectl create secret tls tls-secret \
  --cert=tls.crt \
  --key=tls.key

# Docker registry credentials
kubectl create secret docker-registry registry-creds \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass

Mounting as Environment Variables

# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: app
          image: my-app:1.0
          env:
            # From ConfigMap — a specific key
            - name: DATABASE_HOST
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: DATABASE_HOST
            # From Secret — a specific key
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: DATABASE_PASSWORD
          # Load all keys from a ConfigMap/Secret at once
          envFrom:
            - configMapRef:
                name: app-config
            - secretRef:
                name: app-secrets

Mounting as Files (Volume)

Convenient for configuration files (nginx.conf, .env, application.yaml).

spec:
  containers:
    - name: app
      image: nginx:1.25
      volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
          readOnly: true
        - name: tls-certs
          mountPath: /etc/ssl/certs
          readOnly: true
  volumes:
    - name: nginx-config
      configMap:
        name: nginx-config-map
    - name: tls-certs
      secret:
        secretName: tls-secret

When mounted into a directory, each key from the ConfigMap/Secret becomes a separate file.

# Inside the container:
ls /etc/nginx/conf.d/
# default.conf    upstream.conf

cat /etc/ssl/certs/tls.crt
# -----BEGIN CERTIFICATE-----
# ...

Updating Config Without Restarting

When a ConfigMap or Secret mounted as a volume is changed, the files are updated automatically (with a short delay of ~1 min). Environment variables (env) are not updated — a pod restart is required.

# Edit a ConfigMap
kubectl edit configmap app-config

# Or patch it
kubectl patch configmap app-config \
  --patch '{"data":{"LOG_LEVEL":"debug"}}'

# Force-restart pods in a Deployment
kubectl rollout restart deployment/my-app

Your reaction to the article

💬 Comments (0)

🔐 Sign in to leave a comment
🚪 Login
💭

No comments yet

Be the first to share your opinion about this article!

🔗 Similar

Similar articles

Continue learning with these materials

📝

Health Checks: Liveness and Readiness in Kubernet…

A container is running — that does not mean the application is working. There might...

📅 30.06.2026 👁️ 93
📝

Resource Limits and Requests in Kubernetes

Without resource constraints a single "greedy" container can consume all the memory on a node...

📅 30.06.2026 👁️ 76
📝

What Is Kubernetes and Why You Need It

Docker packages an application into a container. But what do you do when you have...

📅 30.06.2026 👁️ 85

Did you like the article?

Subscribe to our updates and receive new articles first. Grow with PyLand!