12-Factor App and IaC — Deep Dive

Level: Intermediate
Pre-reading: 09 · Deployment & Infrastructure


The 12-Factor App

Factor Principle Implementation
1. Codebase One repo; many deploys Git repo → dev/staging/prod
2. Dependencies Explicitly declared pom.xml, package.json
3. Config In environment Env vars, ConfigMaps
4. Backing services Attached via URL DATABASE_URL
5. Build/Release/Run Strictly separated CI builds → immutable releases
6. Processes Stateless No sticky sessions; state in DB/cache
7. Port binding Export via port App exposes HTTP
8. Concurrency Scale via process Horizontal pod scaling
9. Disposability Fast start/graceful stop SIGTERM handling
10. Dev/Prod parity Keep environments similar Same Docker images
11. Logs Event streams Write to stdout
12. Admin processes One-off tasks K8s Jobs

Config Management

// 12-Factor: Configuration from environment
@Configuration
public class DatabaseConfig {

    @Value("${DATABASE_URL}")
    private String databaseUrl;

    @Value("${DATABASE_POOL_SIZE:10}")
    private int poolSize;
}
# Kubernetes ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-config
data:
  SPRING_PROFILES_ACTIVE: production
  LOG_LEVEL: INFO

Graceful Shutdown

@PreDestroy
public void onShutdown() {
    log.info("Received shutdown signal");
    // Complete in-flight requests
    // Close connections
    // Flush buffers
}
# K8s gives 30s by default
spec:
  terminationGracePeriodSeconds: 60
  containers:
    - lifecycle:
        preStop:
          exec:
            command: ["sh", "-c", "sleep 10"]  # Allow LB to drain

Infrastructure as Code (IaC)

Tool Language Use Case
Terraform HCL Multi-cloud infrastructure
Pulumi TypeScript/Python/Go Programming language IaC
AWS CDK TypeScript/Python AWS infrastructure
Crossplane YAML (K8s CRDs) K8s-native cloud resources

Terraform Example

resource "aws_eks_cluster" "main" {
  name     = "production-cluster"
  role_arn = aws_iam_role.eks.arn
  version  = "1.28"

  vpc_config {
    subnet_ids = var.subnet_ids
  }
}

resource "aws_rds_instance" "orders_db" {
  identifier           = "orders-db"
  engine              = "postgres"
  engine_version      = "15.4"
  instance_class      = "db.t3.medium"
  allocated_storage   = 100

  db_name  = "orders"
  username = "admin"
  password = var.db_password

  multi_az            = true
  skip_final_snapshot = false
}

IaC Best Practices

Practice Rationale
Version control Track changes; review via PRs
Remote state Share state; lock for safety
Modules Reusable components
Environments Separate state per env
CI/CD for infra terraform plan in PR; apply on merge

Why is 'stateless processes' important for microservices?

Stateless processes enable horizontal scaling — any instance can handle any request. No sticky sessions means load balancers can distribute freely. State lives in databases/caches, not in process memory.

Terraform vs Pulumi — when to use which?

Terraform: Industry standard; large ecosystem; declarative HCL. Pulumi: Real programming languages; better for complex logic; smaller ecosystem. Use Terraform for standard infrastructure; consider Pulumi when you need programming constructs.

How do you handle secrets in Terraform?

(1) Don't commit to Git — use .gitignore. (2) Use terraform.tfvars locally; inject in CI. (3) Reference secrets from Vault/AWS SM. (4) Use SOPS for encrypted files. (5) Terraform Cloud/Enterprise has built-in secrets management.