Kubernetes deploy with Helm and Terraform

docker-compose is great for a laptop. Production runs on Kubernetes. Helm charts template the Kubernetes YAML so one chart generates the manifests for dev, staging, and prod. Terraform provisions everything around Kubernetes: the managed database, the object store, the Kafka cluster, the DNS.

Who deploys what

Terraform provisions infra. Helm deploys apps. CI runs both. Keep the layers separate.

Terraform owns infra. Helm owns apps. CI coordinates.
helm/e2e-pipeline/templates/python-api.yaml
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-api
spec:
  replicas: {{ .Values.pythonApi.replicas }}
  selector:
    matchLabels:
      app: python-api
  template:
    metadata:
      labels:
        app: python-api
    spec:
      containers:
        - name: python-api
          image: {{ .Values.pythonApi.image }}
          ports:
            - containerPort: 8000
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health/live
              port: 8000
            initialDelaySeconds: 30
            periodSeconds: 20
          envFrom:
            - secretRef:
                name: python-api-secrets

The FastAPI deployment template. Values come from values.yaml so dev and prod share the same chart. Note the readiness probe points at /health/ready and the liveness probe at /health/live, matching the ported control plane.

Different decisions. Readiness answers "should traffic route to this pod right now?" and pulls the pod out of the load balancer pool when it fails. Liveness answers "is this process alive or should I kill it and restart?" and restarts the pod on failure. Collapsing them causes restart loops the moment a downstream dependency blips.

terraform/postgres.tf
hcl
resource "aws_db_instance" "warehouse" {
  identifier        = "pipeline-warehouse"
  engine            = "postgres"
  engine_version    = "15"
  instance_class    = "db.t4g.medium"
  allocated_storage = 100
  username          = var.db_username
  password          = var.db_password
  skip_final_snapshot = false
  backup_retention_period = 14
  tags = {
    Environment = var.environment
    Owner       = "data-platform"
  }
}

A minimal Terraform module that provisions a managed Postgres instance. Terraform keeps state so every change is a diff, and rollback is a terraform apply to a previous version.

Quiz: Quiz

Loading practice…