Terraform and Helm
How I split infra (Terraform) from app deploys (Helm) at Binocs, and the boundary between the two.
Terraform manages infrastructure: VPC, subnets, EKS cluster, RDS, IAM, S3, ECR. Helm packages and deploys applications onto Kubernetes: Deployments, Services, ConfigMaps, Ingress. The boundary is the cluster itself. Terraform creates it, Helm fills it.
What I built at Binocs
Three Terraform repos:
infra-base: VPC, NAT gateways, security groups, IAM baselines. Run once per environment.infra-platform: EKS cluster, node groups, RDS, ElastiCache, ECR repos. Depends on base.infra-app: per-app resources like S3 buckets, SQS queues, IAM roles for IRSA. Many of these.
State in S3 with DynamoDB locking. Workspaces for dev/staging/prod. Modules for repeatable patterns (a "service" module that wires up ECR + IAM role + secret).
Helm charts in a separate repo, one chart per service, deployed via ArgoCD watching the main branch.
Why split it
- Terraform plans are slow (30+ seconds against AWS APIs). You do not want this in the inner loop of app deploys.
- Helm is fast (sub-second template + apply via kubectl).
- App teams ship daily, infra changes weekly. Different cadences, different reviewers.
- State conflicts: Terraform's kubernetes provider and kubectl/Helm both want to own resources. Pick one per resource.
Helm essentials
A chart is a templated bundle of Kubernetes manifests. values.yaml provides defaults, values-prod.yaml overrides. Templates use Go template syntax with Sprig functions.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "app.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
resources:
{{- toYaml .Values.resources | nindent 10 }}Helm tracks releases in a ConfigMap (or Secret) per release. helm upgrade --atomic rolls back on failure. helm diff (plugin) shows what will change before applying.
Terraform essentials
State is everything. Lose it and you lose the link between code and reality. Store it remotely, lock it, back it up. Never commit terraform.tfstate to git.
Modules: factor common patterns. A service module that creates ECR repo, IAM role, IRSA binding. Call it N times for N services.
Plan, review, apply. Never apply without reviewing the plan. CI should plan on every PR and post the diff as a comment.
Learn more
- DocsTerraform DocumentationHashiCorp
- Docs
- DocsTerraform AWS ProviderHashiCorp