Inject ConfigMaps into Python Pods

Inject ConfigMaps into Python pods as environment — Kubernetes for Python Developers. Learn how to expose configuration data to your Python apps via ConfigMaps, with hands-on steps, troubleshooting, and what's next.

Focus: inject configmaps into python pods as environment

Sponsored

Every Python developer knows the pain: your app works perfectly in local development, but the moment you deploy to Kubernetes, settings like database URLs, API keys, and feature flags are either hardcoded, scattered across multiple YAML files, or worse — baked into the container image at build time. Changing a single environment variable means rebuilding an image, pushing it to a registry, and rolling out a new deployment. That workflow is slow, error-prone, and a security nightmare. This lesson shows you how to inject ConfigMaps into Python pods as environment variables — the Kubernetes-native way to manage configuration separately from your code, so you can change settings on the fly without touching your image or redeploying from scratch.

The problem this lesson solves

When you run a Python app in Kubernetes, the container needs configuration: a DATABASE_URL, an API_KEY, a LOG_LEVEL, maybe a FEATURE_FLAG. Where does that come from? The naive answers all fail in production:

  • Hardcoding the value in your Python source means a config change requires a code change, a commit, a CI build, a new image, and a rollout. Slow and risky.
  • Storing config in the container image via environment variables defined in the Dockerfile (e.g., ENV DATABASE_URL=...) bakes the value into every image. You can't change it without rebuilding, and you'll accidentally leak secrets into your image registry if you're not careful.
  • Mounting a config file works, but requires the file to exist on disk and complicates how your app reads it.

Kubernetes gives you a dedicated resource for non-sensitive configuration: the ConfigMap. It's a simple key-value store designed exactly for this. When you inject a ConfigMap into a Python pod as environment variables, you decouple configuration from your code and image. You update the ConfigMap, your app picks up the new value on the next pod restart, and you never rebuild an image again.

Core concept / mental model

Think of a ConfigMap as a post-it note board on your cluster. Your Python pod is a task that needs to read those notes. Instead of writing the notes on the task itself (hardcoding) or gluing them to the task's container (baking into the image), you pin them to the board and let the task read them.

Concretely, a ConfigMap is a Kubernetes API object that holds key-value pairs. A pod can consume it in two ways:

  • As environment variables — each key becomes an env var in your container, accessible via os.environ.
  • As files in a volume — each key becomes a file in a mounted directory, useful for config files like app.ini or logging.json.

For this lesson, focus on environment variables, the most common pattern for Python apps. The flow looks like this:

  1. You create a ConfigMap with your configuration data.
  2. You reference the ConfigMap in your pod's spec under envFrom or valueFrom.
  3. Kubernetes injects the values as environment variables into your Python container.
  4. Your Python code reads them with os.environ.get("KEY").

This works exactly like the env vars you set locally, so your app code stays clean and portable.

How it works step by step

Let's break down the mechanism:

  1. Create the ConfigMap — You define a YAML manifest with apiVersion: v1, kind: ConfigMap, and a data map. Keys are strings that become environment variable names; values are the configuration strings. (Values are always strings — numbers and booleans must be quoted.)

  2. Reference the ConfigMap in the pod spec — There are two ways: - envFrom: Injects every key in the ConfigMap as an environment variable. Fastest, but you can't control which keys arrive (all of them do). - env with valueFrom: Injects a specific key under a chosen env var name. More explicit, gives you renaming and selective injection.

  3. Deploy the pod — Kubernetes API server stores the ConfigMap, and the kubelet on the node reads it when starting your container.

  4. Your Python app reads the env var — import os and use os.getenv("MY_KEY", "default") in your code.

  5. Update behavior — If you change the ConfigMap data, Kubernetes does NOT update env vars in running pods. You must restart the pod (e.g., kubectl rollout restart deployment/my-app) for the new values to take effect. This is a critical detail — env vars are injected at container start, not dynamically.

The key insight: ConfigMaps are not secrets. They are for non-sensitive data like public endpoints, feature flags, log levels. For credentials, you'll use a Secret — the next lesson in this track.

Hands-on walkthrough

Let's put this into action. You'll need a running Kubernetes cluster (minikube, kind, or Docker Desktop with Kubernetes) and kubectl configured.

Step 1: Create your Python app

Start with a minimal Flask app that reads a config value from the environment:

# app.py
from flask import Flask
import os

app = Flask(__name__)

APP_NAME = os.getenv("APP_NAME", "unknown")
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
FEATURE_FLAG = os.getenv("FEATURE_FLAG", "false").lower() == "true"

@app.route("/")
def index():
    return f"App: {APP_NAME} | Log: {LOG_LEVEL} | Feature flag: {FEATURE_FLAG}"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Step 2: Build and push the image

# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

requirements.txt: flask==3.0.0

Build and push to a registry (here we use a local minikube registry, but you can use Docker Hub or any registry):

eval $(minikube docker-env)  # if using minikube
docker build -t my-python-app:latest .
docker tag my-python-app:latest myregistry/my-python-app:latest
docker push myregistry/my-python-app:latest  # skip if using minikube docker-env

Step 3: Create the ConfigMap

Create configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_NAME: "My Python Service"
  LOG_LEVEL: "DEBUG"
  FEATURE_FLAG: "true"

Apply it:

kubectl apply -f configmap.yaml

Step 4: Deploy the pod that uses the ConfigMap

Create deployment.yaml using 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: myregistry/my-python-app:latest
        ports:
        - containerPort: 5000
        envFrom:
        - configMapRef:
            name: app-config

Apply it:

kubectl apply -f deployment.yaml

Step 5: Verify the injection

Check the pod's environment variables:

kubectl exec -it deploy/python-app -- env | grep -E 'APP_NAME|LOG_LEVEL|FEATURE_FLAG'

Expected output:

APP_NAME=My Python Service
LOG_LEVEL=DEBUG
FEATURE_FLAG=true

Now expose the app and test:

kubectl expose deployment python-app --type=NodePort --port=5000
minikube service python-app # or get the node port and curl

Expected output:

App: My Python Service | Log: DEBUG | Feature flag: True

Optional: Selective injection with valueFrom

If you want to rename a key or inject only some keys, use env with valueFrom:

        env:
        - name: SERVICE_NAME
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_NAME
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: LOG_LEVEL

Now the pod has SERVICE_NAME and LOG_LEVEL, but not FEATURE_FLAG.

Update flow

Edit the ConfigMap to change a value:

kubectl edit configmap app-config

Change LOG_LEVEL to INFO, save. Then restart the deployment to apply:

kubectl rollout restart deployment/python-app

Now if you exec and check, the new value is there.

Pro tip: Always use os.getenv("KEY", "default") in your Python code. This makes your app resilient to missing config, which helps during local development and testing when the injected env vars aren't present.

Compare options / when to choose what

When injecting ConfigMaps into Python pods, you have several approaches. Here's a quick comparison:

Approach Pros Cons Best for
envFrom (all keys) Fast, no duplication, auto-sync with ConfigMap Injects everything — you might get unexpected vars; can't rename Simple apps, configs with many keys
env + valueFrom (specific keys) Explicit, allows renaming, selective Verbose; you must list every var Apps that need a curated set of env vars
Mount ConfigMap as volume Works for file-based config (init files, .env), can reload Requires file I/O in your app; more complex Apps that read config from files (e.g., configparser)
Use a Secret instead Handles sensitive data, base64-encoded Still encoded, not encrypted; more complexity Credentials, passwords (see next lesson)
Helm / Kustomize templating Dynamic values per environment Adds tooling overhead Multi-environment deployments

For most Python microservices, start with envFrom — it's the least code and aligns with 12-factor app principles. If you need to rename keys or avoid injecting unrelated keys, switch to valueFrom.

Note: envFrom and env can be combined. You can use envFrom for bulk and env to override a specific key. Pod-level env vars take precedence if names clash.

Troubleshooting & edge cases

Here are the common issues you'll hit:

  • Env var not showing up — Check that your pod spec references the ConfigMap correctly. Run kubectl describe pod <pod-name> and look for the Environment: section. If you see an error like configmap "app-config" not found, you forgot to create it or the name is wrong.
  • Variable value contains special characters — If your value has $, backticks, or spaces, YAML may parse it incorrectly. Quote the value: APP_NAME: "My $ervice".
  • Numeric or boolean values — In a ConfigMap, all values are strings. So count: 3 becomes "3". In Python, os.getenv("COUNT") returns "3" — you must convert to int() if needed. Same for booleans: compare with .lower() == "true".
  • ConfigMap not found in pod — Make sure the ConfigMap is in the same namespace as the pod. Use kubectl get configmap -n <namespace>.
  • Changes not reflected — Env vars are injected at container start. After updating the ConfigMap, you must restart the pod/deployment. kubectl rollout restart deployment/your-app is your friend.
  • envFrom conflicts with pod's existing env — The pod-level env overrides envFrom. If you have both and see unexpected values, check which one is winning.
  • Deployment fails with MountVolume.SetUp failed — This is for volume mounts, but if you're using envFrom and see a mount error, you might have accidentally mixed syntax. Double-check indentation in your YAML.

Pro tip: Use kubectl get configmap app-config -o yaml to inspect the actual data stored. And kubectl exec -it <pod> -- env | sort to see all env vars in the pod.

What you learned & what's next

You've learned how to inject ConfigMaps into Python pods as environment variables — the Kubernetes-native way to manage configuration. You now know how to create a ConfigMap, reference it in a deployment using envFrom or valueFrom, and read the values in your Python app with os.getenv. You also understand the update flow and the critical difference between ConfigMaps and Secrets: ConfigMaps are for non-sensitive data, Secrets for credentials.

With configuration handled, the natural next step in this track is Secrets — how to inject sensitive data like API keys and database passwords securely, using the same injection patterns but with proper encryption and access controls. That's already waiting for you in the next lesson.

Keep practicing: create a ConfigMap with a few keys, inject them into a simple Python service, change a value, and restart — you'll be amazed at how much smoother your deployment workflow becomes.

Practice recap

Try this: create a new ConfigMap called my-settings with keys DEBUG_LVL and MAX_RETRIES. Deploy a simple Python pod that references it with envFrom and prints those values. Then update the ConfigMap, restart the deployment, and verify the new values appear. This reinforces the injection and update flow hands-on.

Common mistakes

  • Forgetting to quote string values in ConfigMap YAML — numbers and booleans are treated as strings, causing type errors in Python if you don't convert them.
  • Updating a ConfigMap but not restarting the pod — env vars are only injected at container start, so changes don't take effect until you restart.
  • Using a ConfigMap for secrets — ConfigMaps are not encrypted and are visible to anyone with RBAC access; use Secrets instead.
  • Mixing envFrom and env and expecting env to override — env takes precedence, but you might accidentally shadow a value you didn't intend.

Variations

  1. Mount the ConfigMap as a volume (e.g., at /etc/config) and read files from disk — useful for file-based config formats like .env or configparser.
  2. Use Helm or Kustomize to generate ConfigMap values per environment (dev, staging, prod) from templates.
  3. Use env with configMapKeyRef for renaming keys or picking specific entries when you don't want to inject all keys.

Real-world use cases

  • A Flask or FastAPI microservice that reads its database connection string and log level from a ConfigMap injected as env vars, so you can change them per environment without image rebuilds.
  • A Python worker (like Celery or a Kafka consumer) that reads feature flags from a ConfigMap to toggle behaviors dynamically after a rollout restart.
  • A Django app that needs a DJANGO_SETTINGS_MODULE and ALLOWED_HOSTS injected from ConfigMaps, keeping the same Docker image across staging and production.

Key takeaways

  • ConfigMaps store non-sensitive key-value configuration and can be injected into Python pods as environment variables.
  • Use envFrom to inject all keys, or env with valueFrom for selective, renamed variables.
  • Your Python code reads injected values via os.getenv() — always provide a sensible default.
  • Env vars are set at container start; after updating a ConfigMap, restart the pod to apply changes.
  • ConfigMaps are not secrets — never store passwords or API keys in them; use Secrets instead.
  • Keep configuration out of your image to make it portable across environments and avoid rebuild cycles.

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.