Core Concepts
5 min readRapid overview
- Infrastructure as Code (IaC)
- Terraform
- Basic Structure
- Variables and Outputs
- Modules
- State Management
- Workspaces
- Helm Charts
- Chart Structure
- Chart.yaml
- Values and Templates
- Helm Commands
- GitOps with Argo CD
- Application Definition
- ApplicationSet
- Kustomize
- Structure
- Base Kustomization
- Overlay Kustomization
- Interview Questions
- 1. Explain Terraform state and why it's important
- 2. What is GitOps?
- 3. Helm vs Kustomize - when to use each?
- 4. How do you manage secrets in IaC?
Infrastructure as Code (IaC)
Terraform
Basic Structure
# main.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "terraform"
Project = var.project_name
}
}
}
Variables and Outputs
# variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_config" {
description = "EC2 instance configuration"
type = object({
instance_type = string
ami_id = string
volume_size = number
})
default = {
instance_type = "t3.micro"
ami_id = "ami-0123456789"
volume_size = 20
}
}
# outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs of public subnets"
value = aws_subnet.public[*].id
}
Modules
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.name}-vpc"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.name}-public-${count.index + 1}"
Type = "public"
}
}
# Using the module
module "vpc" {
source = "./modules/vpc"
name = "production"
vpc_cidr = "10.0.0.0/16"
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
availability_zones = ["us-east-1a", "us-east-1b"]
}
State Management
# Import existing resources
terraform import aws_instance.web i-1234567890abcdef0
# Move resources between states
terraform state mv aws_instance.old aws_instance.new
# Remove from state (doesn't delete resource)
terraform state rm aws_instance.orphan
# List resources in state
terraform state list
Workspaces
# Create workspace
terraform workspace new staging
# Switch workspace
terraform workspace select prod
# List workspaces
terraform workspace list
# Use in configuration
resource "aws_instance" "web" {
instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
}
Helm Charts
Chart Structure
mychart/
├── Chart.yaml
├── values.yaml
├── values-prod.yaml
├── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ └── hpa.yaml
└── charts/ # Dependencies
Chart.yaml
apiVersion: v2
name: myapp
description: My Application Helm Chart
type: application
version: 1.0.0
appVersion: "2.1.0"
dependencies:
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
Values and Templates
# values.yaml
replicaCount: 2
image:
repository: myapp
tag: "" # Defaults to appVersion
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
Helm Commands
# Install
helm install myrelease ./mychart -f values-prod.yaml -n production
# Upgrade
helm upgrade myrelease ./mychart -f values-prod.yaml -n production
# Install or upgrade
helm upgrade --install myrelease ./mychart -f values-prod.yaml -n production
# Rollback
helm rollback myrelease 1 -n production
# Show computed values
helm get values myrelease -n production
# Template locally (debug)
helm template myrelease ./mychart -f values-prod.yaml
# Lint
helm lint ./mychart
GitOps with Argo CD
Application Definition
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo
targetRevision: HEAD
path: kubernetes/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
ApplicationSet
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-apps
namespace: argocd
spec:
generators:
- clusters:
selector:
matchLabels:
environment: production
template:
metadata:
name: '{{name}}-myapp'
spec:
project: default
source:
repoURL: https://github.com/org/repo
targetRevision: HEAD
path: kubernetes/overlays/{{metadata.labels.environment}}
destination:
server: '{{server}}'
namespace: myapp
Kustomize
Structure
kubernetes/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── replica-patch.yaml
└── prod/
├── kustomization.yaml
├── replica-patch.yaml
└── resource-patch.yaml
Base Kustomization
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: myapp
Overlay Kustomization
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
namePrefix: prod-
commonLabels:
environment: production
images:
- name: myapp
newTag: v2.1.0
replicas:
- name: myapp
count: 5
patches:
- path: replica-patch.yaml
- patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources/limits/memory
value: 1Gi
target:
kind: Deployment
name: myapp
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
- ENVIRONMENT=production
secretGenerator:
- name: app-secrets
envs:
- secrets.env
Interview Questions
1. Explain Terraform state and why it's important
- State tracks resource mapping between config and real infrastructure
- Enables plan/apply to determine what changes are needed
- Must be protected (sensitive data, locking for teams)
- Use remote backends (S3, Azure Blob) for team collaboration
2. What is GitOps?
- Infrastructure and application configs stored in Git
- Git as single source of truth
- Changes through pull requests
- Automated sync between Git and cluster
- Benefits: audit trail, rollback via git revert, declarative
3. Helm vs Kustomize - when to use each?
Helm:
- Complex templating needs
- Packaging for distribution
- Dependency management
- Release management with rollback
Kustomize:
- Simple overlays on base configs
- No templating complexity
- Built into kubectl
- Pure YAML, easier to understand
4. How do you manage secrets in IaC?
- Don't commit secrets - use .gitignore
- External secret management - Vault, AWS Secrets Manager
- Encrypted secrets - SOPS, Sealed Secrets
- Environment variables - injected at runtime
- Terraform - sensitive variables, remote state encryption