Skip to main content
โšก Calmops

Configuration Management: Environment Variables, Config Maps, and 12-Factor Apps

Introduction

Configuration management separates configuration from code, enabling deployments across environments without code changes. The 12-factor app methodology provides principles for building portable, scalable applications.

Environment Variables

import os
from dataclasses import dataclass
from typing import Optional

@dataclass
class Config:
    """Application configuration from environment variables."""
    
    # Required
    database_url: str
    redis_url: str
    secret_key: str
    
    # Optional with defaults
    log_level: str = "INFO"
    debug: bool = False
    max_connections: int = 10
    timeout: int = 30
    
    @classmethod
    def from_env(cls) -> "Config":
        return cls(
            database_url=os.getenv("DATABASE_URL"),
            redis_url=os.getenv("REDIS_URL", "redis://localhost:6379"),
            secret_key=os.getenv("SECRET_KEY"),
            log_level=os.getenv("LOG_LEVEL", "INFO"),
            debug=os.getenv("DEBUG", "false").lower() == "true",
            max_connections=int(os.getenv("MAX_CONNECTIONS", "10")),
            timeout=int(os.getenv("TIMEOUT", "30"))
        )

# Usage
config = Config.from_env()
if not config.database_url:
    raise ValueError("DATABASE_URL is required")

12-Factor App Principles

# I. Codebase: One codebase, many deployments
# - Single repo per app
# - Deploy to dev, staging, production

# II. Dependencies: Explicitly declare dependencies
# requirements.txt
# package.json
# Use virtual environments

# III. Config: Store config in environment
# Database URLs, API keys, feature flags
# NOT in code

# IV. Backing Services: Treat as attached resources
# Database = attached service
# Redis cache = attached service
# Email service = attached service

# V. Build, Release, Run: Strict separation
# Build: compile/code -> artifact
# Release: artifact + config -> runnable
# Run: execute release

# VI. Processes: Stateless
# No local state
# Use Redis for session state
# Filesystem for temp only

# VII. Port Binding: Export services via port binding
# Web: listen on port 8000
# API: listen on port 8080

# VIII. Concurrency: Scale via process model
# Web: multiple processes
# Workers: background processes

# IX. Disposability: Fast startup and shutdown
# Graceful shutdown handling
# No SIGKILL without cleanup

# X. Dev/Prod Parity: Keep environments similar
# Same OS, same tools
# Minimize gaps

# XI. Logs: Treat logs as event streams
# Write to stdout
# Aggregate with ELK/Splunk

# XII. Admin Processes: Run admin tasks in same environment
# Migrations
# Console/REPL
# One-off jobs

Secrets Management

import os
from abc import ABC, abstractmethod

class SecretsManager(ABC):
    """Abstract secrets manager."""
    
    @abstractmethod
    def get_secret(self, key: str) -> str:
        pass
    
    @abstractmethod
    def set_secret(self, key: str, value: str):
        pass

class EnvironmentSecretsManager(SecretsManager):
    """Secrets from environment variables."""
    
    def get_secret(self, key: str) -> str:
        return os.getenv(key)
    
    def set_secret(self, key: str, value: str):
        os.environ[key] = value

class AWSSecretsManager(SecretsManager):
    """Secrets from AWS Secrets Manager."""
    
    def __init__(self):
        import boto3
        self.client = boto3.client("secretsmanager")
    
    def get_secret(self, key: str) -> str:
        response = self.client.get_secret_value(SecretId=key)
        secrets = json.loads(response["SecretString"])
        return secrets.get(key)
    
    def set_secret(self, key: str, value: str):
        # Update secret
        pass

# Usage
secrets = AWSSecretsManager()
api_key = secrets.get_secret("api-key")

Conclusion

Configuration management is critical for deployability. Store config in environment, not code. Use secrets managers for sensitive data. Follow 12-factor principles for portability. Keep dev/prod parity.

Resources

  • 12factor.net
  • AWS Secrets Manager Documentation

Comments