Create ConfigMaps for Python Apps

Create ConfigMaps for Python app settings in this Kubernetes for Python Developers tutorial — hands-on steps, troubleshooting, and what to study next.

Focus: create configmaps for python app settings

Sponsored

You've built a sleek Python service, wrapped it in a Docker image, and pushed it to a registry. But now comes the part that breaks every deployment: your app's settings are hard-coded, or worse, baked into the image. A teammate changes a database URL, a QA engineer tweaks a log level, and suddenly you're rebuilding images and redeploying just to change a string. That's the pain this lesson eliminates. By the end, you'll be able to create ConfigMaps for Python app settings — keeping configuration out of your image and under the control of Kubernetes, so you can change behavior without a single rebuild.

The problem this lesson solves

Imagine your Flask or FastAPI app has a config.py that reads environment variables like DATABASE_URL, REDIS_HOST, and LOG_LEVEL. In development, you set them in a .env file. But in Kubernetes, you need a clean, versionable way to inject those values into your pods. Hard-coding them in the image is a recipe for disaster: every change forces a rebuild, a push, and a redeploy. That's slow, error-prone, and breaks the promise of immutable containers.

Kubernetes offers ConfigMaps, a built-in API object designed exactly for this. A ConfigMap lets you store configuration data as key-value pairs or even as entire files, separate from your containerized Python application. You can then present that data to your pods as environment variables, mounted files, or command-line arguments. This decouples your app's behavior from its packaging, giving you:

  • Configuration portability: The same image runs in dev, staging, and prod — just point to different ConfigMaps.
  • Operational agility: Update a setting and restart (or trigger a rollout) without touching the code or image.
  • Team collaboration: Developers own the code; operators own the configuration. No more merge conflicts on config.py.

Core concept / mental model

Think of a ConfigMap as a dictionary that Kubernetes hands to your app at runtime. Just like a Python dict maps keys to values, a ConfigMap maps string keys to string values. But instead of accessing it with config["DEBUG"], your app reads it through environment variables or files that Kubernetes injects into the pod.

Analogy: Your Docker image is a CD-ROM — fixed and immutable. A ConfigMap is a sticky note you place on the pod before it starts. The CD-ROM's code reads whatever the sticky note says. Change the note, restart the pod, and the code behaves differently — no new CD-ROM needed.

A ConfigMap lives in the cluster (etcd) and is namespaced. It does not provide encryption — that's what Secrets are for. ConfigMaps are for non-sensitive data like URLs, port numbers, feature flags, and log levels. Treat them as unclassified.

Pro tip: A ConfigMap is just data. It doesn't "do" anything by itself. Your Python code must be written to consume environment variables or read files from a known path. If your code doesn't do that, a ConfigMap won't help.

How it works step by step

Creating and using a ConfigMap for your Python app follows a predictable flow:

  1. Prepare your Python app to read configuration from the environment or a file. Use os.getenv() or a library like python-dotenv (but in Kubernetes, the environment is already set).
  2. Define the ConfigMap manifest in YAML. Give it a name, a namespace, and your key-value pairs under data or stringData (the latter allows non-string types but is usually unnecessary).
  3. Apply the ConfigMap to the cluster with kubectl apply -f configmap.yaml.
  4. Reference the ConfigMap in your Pod or Deployment spec. Two common ways: envFrom to inject all keys as environment variables, or valueFrom/configMapKeyRef to pick specific keys.
  5. Deploy your Python app with the updated manifest. Kubernetes mounts the ConfigMap data into the container before the app starts.

That's it. Your Python code never knows about ConfigMaps — it just sees environment variables or files. This separation is the core design principle of twelve-factor apps.

The key insight: the ConfigMap is created once, but its values are read at pod creation. If you change a ConfigMap, existing pods don't see the change until they restart. For a Deployment, a simple kubectl rollout restart will pick up the new values.

Hands-on walkthrough

Let's create a ConfigMap for a realistic Python app. We'll use a fictional FastAPI service that needs DATABASE_URL, LOG_LEVEL, and MAX_CONNECTIONS.

First, a minimal app.py that reads environment variables:

import os
from fastapi import FastAPI

app = FastAPI()

DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://localhost/default")
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
MAX_CONNECTIONS = int(os.getenv("MAX_CONNECTIONS", "10"))

@app.get("/")
def root():
    return {
        "database": DATABASE_URL,
        "log_level": LOG_LEVEL,
        "max_connections": MAX_CONNECTIONS
    }

Now, create a ConfigMap manifest configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: python-app-config
  namespace: default
data:
  DATABASE_URL: "postgresql://user:pass@db.internal:5432/mydb"
  LOG_LEVEL: "DEBUG"
  MAX_CONNECTIONS: "100"

Apply it:

kubectl apply -f configmap.yaml
# configmap/python-app-config created

Now, create a Deployment deployment.yaml that injects the ConfigMap via envFrom:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-app
  template:
    metadata:
      labels:
        app: python-app
    spec:
      containers:
        - name: python-app
          image: myrepo/python-app:latest
          ports:
            - containerPort: 8000
          envFrom:
            - configMapRef:
                name: python-app-config

Deploy the app and check the output:

kubectl apply -f deployment.yaml
kubectl get pods
kubectl logs <pod-name>

If your app logs the config, you'll see the ConfigMap values appear. If you curl the root endpoint, you'll get:

{"database":"postgresql://user:pass@db.internal:5432/mydb","log_level":"DEBUG","max_connections":100}

Notice that MAX_CONNECTIONS was injected as a string, and your Python code cast it to int. That's a common gotcha — we'll cover it in troubleshooting.

Compare options / when to choose what

You have two main ways to expose ConfigMap data to your Python container: as environment variables or as mounted files. Each has trade-offs.

Approach How it works Best for Downsides
Environment variables (envFrom or valueFrom) Kubernetes sets env vars in the container Simple settings, quick access in code via os.getenv Values are strings; large configs become unwieldy; no hot reload
Mounted Volume (via volumes and volumeMounts) ConfigMap keys become files in a directory Complex configs (e.g., settings.py, .env, JSON/XML files) You must implement file reading; changes require pod restart (or custom reload)
Command-line args Use valueFrom to set an arg Single values that affect startup behavior Limited to a few values; awkward for many keys

For most Python apps, environment variables are the simplest and most idiomatic, especially if you follow twelve-factor principles. But if your app expects a config file (like Django's settings.py or a .env file), mounting is cleaner. You can even mount a single file by creating a ConfigMap with a key that holds the file content.

Troubleshooting & edge cases

1. My environment variable is missing — Check that the ConfigMap exists and the key name matches exactly. ConfigMap keys must be valid env var names (uppercase letters, digits, underscores) if you use envFrom. If you use valueFrom, the key can be anything, but the env var name is what you define. Use kubectl get configmap python-app-config -o yaml to verify.

2. Values are strings, and my app expects an int/bool — Kubernetes env vars are always strings. Convert in Python: int(os.getenv("MAX_CONNECTIONS", "10")) or parse booleans with os.getenv("DEBUG", "false").lower() == "true". Never assume the type.

3. ConfigMap changes don't take effect — ConfigMaps are read at pod creation. If you edit the ConfigMap, running pods keep the old values. For a Deployment, run kubectl rollout restart deployment/python-app to force new pods that pick up the new data.

4. Special characters break the ConfigMap — If your value contains a colon, newline, or a leading/trailing space, you must quote it in YAML. For multi-line values, use a block scalar | or >. Example:

data:
  SQL_QUERY: |
    SELECT * FROM users
    WHERE active = true;

5. envFrom silently fails on invalid keys — If a key in the ConfigMap is not a valid env var name (e.g., contains a hyphen), Kubernetes will skip it and log a warning. A common symptom is a missing variable. Always use uppercase with underscores for keys intended as env vars.

6. Mounted file permissions — When you mount a ConfigMap as a volume, files get default permissions (0644). If your Python app needs to write to that file (you shouldn't — ConfigMaps are read-only), you'll fail. Design your app to treat mounted config files as read-only.

7. Secrets vs ConfigMaps — don't mix them up — Never put passwords, tokens, or API keys in a ConfigMap. Use Secret (which is base64-encoded, not encrypted by default) or a dedicated secret manager. ConfigMaps are for non-sensitive settings.

What you learned & what's next

You now know how to create ConfigMaps for Python app settings — the fundamental way to keep configuration external from your container image. You can define a ConfigMap, inject its values as environment variables or files, and update behavior without rebuilding your Docker image. You also understand common pitfalls like type conversion, immutability at runtime, and the difference between ConfigMaps and Secrets.

This skill is the backbone of every production-grade Python service on Kubernetes. Next in this track, you'll learn about Secrets — the same model but for sensitive data like API keys and database passwords. After that, you'll combine ConfigMaps and Secrets to deploy a complete, configurable Python microservice. You're building the operational muscle that separates a demo app from a production system.

Pro tip: Before moving on, practice by creating a ConfigMap for a simple Flask app you already have. Try injecting three settings, then update the ConfigMap and restart the deployment. You'll see the change in seconds — that speed is the whole point.

Practice recap

Create a ConfigMap for a simple Python script that reads GREETING and TIMES from environment variables. Run it as a pod or locally with kubectl exec, then update the ConfigMap and restart to see the greeting change. This will cement the workflow you'll use in the Secrets lesson next.

Common mistakes

  • Putting secrets or passwords in a ConfigMap instead of using a Secret — ConfigMaps are not encrypted.
  • Assuming environment variable values are not strings — always convert to int/bool in Python.
  • Forgetting that ConfigMap changes don't auto-apply to running pods — you must restart the deployment.
  • Using a key name with a hyphen or lowercase that fails env var validation when using envFrom.

Variations

  1. Instead of envFrom, use valueFrom/configMapKeyRef to inject only specific keys as environment variables.
  2. Mount the ConfigMap as a volume and read a config file (e.g., settings.yaml) with Python's yaml library.
  3. Use a Helm chart to templatize ConfigMaps and auto-generate them per environment (dev/staging/prod).

Real-world use cases

  • A FastAPI microservice reads DATABASE_URL, REDIS_HOST, and LOG_LEVEL from a ConfigMap so the same image runs in dev and prod with just a kubectl apply.
  • A Django app mounts a ConfigMap containing a custom settings.py file that overrides base configuration per environment without rebuilding the image.
  • A data processing pipeline loads feature flags and thresholds from a ConfigMap, allowing ops to change them and restart the batch job without touching code.

Key takeaways

  • ConfigMaps separate configuration from container images — change settings with kubectl, not a rebuild.
  • ConfigMaps are key-value stores, and all values are strings; convert them in Python as needed.
  • Inject ConfigMaps as environment variables via envFrom or as mounted files for complex configs.
  • ConfigMaps are read-only and not encrypted — use Secrets for sensitive data.
  • Changes to a ConfigMap don't affect running pods; use kubectl rollout restart for Deployments.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.