Why Infrastructure as Code?
Clicking through the AWS console is fine for experimenting. It's a disaster for production. You can't version it, review it, or reproduce it reliably. That's exactly what Terraform solves — you describe your infrastructure in code, commit it to Git, and apply it the same way everywhere.
Core Terraform Concepts
- Provider — the platform you're targeting (AWS, GCP, Azure, etc.)
- Resource — a piece of infrastructure to create (EC2 instance, S3 bucket, VPC)
- State — Terraform's record of what it has created
- Plan — a preview of changes before applying them
Step 1: Install and Configure Terraform
# macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# Verify
terraform version
# Configure AWS credentials
aws configure
# Enter your AWS Access Key ID, Secret, and default region
Step 2: Your First Terraform Project
Create a directory and a main.tf file:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}
# Create an S3 bucket
resource "aws_s3_bucket" "devops_artifacts" {
bucket = "devopspack-artifacts-${random_id.suffix.hex}"
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
resource "random_id" "suffix" {
byte_length = 4
}
# Output the bucket name
output "bucket_name" {
value = aws_s3_bucket.devops_artifacts.bucket
}
Step 3: Init, Plan, Apply
# Download providers
terraform init
# Preview what will be created (no changes made)
terraform plan
# Create the resources
terraform apply
# Type 'yes' when prompted
Terraform will print the bucket name as output. Check your AWS console — the bucket is there.
Step 4: Remote State with S3 Backend
Never store state locally in a team environment. Use S3 + DynamoDB for locking:
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "prod/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Step 5: Organize with Modules
As your infra grows, group related resources into modules:
modules/
vpc/
main.tf
variables.tf
outputs.tf
ec2/
main.tf
variables.tf
outputs.tf
Reference a module like this:
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
environment = "production"
}
Best Practices
- Always run
terraform planbeforeapply— treat it like a code review - Store state remotely — never commit
.tfstatefiles to Git - Use workspaces or separate state files for dev/staging/prod environments
- Tag every resource with
Environment,ManagedBy, andOwner - Lock provider versions to avoid surprise breaking changes

Member discussion