🔧 Week 7: Infrastructure as Code

Day 2: Terraform Basics

⏱ Duration: 5 Hours

📚 Learning Objectives

  • Understand Terraform providers and resources
  • Work with variables and outputs
  • Master terraform init, plan, apply workflow
  • Learn Terraform file structure and syntax

📖 Core Concepts (2 Hours)

Terraform File Structure

my-terraform-project/ ├── main.tf # Main configuration (resources) ├── variables.tf # Input variable declarations ├── outputs.tf # Output value declarations ├── terraform.tfvars # Variable values (don't commit secrets!) ├── providers.tf # Provider configurations └── .terraform/ # Downloaded providers (gitignore this)

Providers

Providers are plugins that Terraform uses to interact with cloud APIs.

# providers.tf terraform { required_version = ">= 1.0.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } # Configure the AWS Provider provider "aws" { region = "us-east-1" # Optional: Use specific profile # profile = "my-aws-profile" default_tags { tags = { Environment = "Development" ManagedBy = "Terraform" } } }

Resources

Resources are the infrastructure objects Terraform manages.

# Resource syntax: # resource "TYPE" "NAME" { # argument = value # } # Example: S3 Bucket resource "aws_s3_bucket" "my_bucket" { bucket = "my-unique-bucket-name-12345" tags = { Name = "My Terraform Bucket" } } # Reference other resources resource "aws_s3_bucket_versioning" "my_bucket_versioning" { bucket = aws_s3_bucket.my_bucket.id # Reference! versioning_configuration { status = "Enabled" } }

Variables

# variables.tf - Declare variables variable "region" { description = "AWS region to deploy to" type = string default = "us-east-1" } variable "instance_type" { description = "EC2 instance type" type = string default = "t2.micro" } variable "allowed_ports" { description = "List of allowed ports" type = list(number) default = [22, 80, 443] } variable "tags" { description = "Tags for resources" type = map(string) default = { Environment = "dev" Project = "demo" } } # Use variables with var.name provider "aws" { region = var.region }

Variable Values

# terraform.tfvars - Set values region = "us-west-2" instance_type = "t3.micro" allowed_ports = [22, 80, 443, 8080] tags = { Environment = "production" Project = "webapp" } # Or pass via command line: terraform apply -var="region=us-west-2" # Or environment variables: export TF_VAR_region="us-west-2"

Outputs

# outputs.tf output "bucket_name" { description = "Name of the S3 bucket" value = aws_s3_bucket.my_bucket.id } output "bucket_arn" { description = "ARN of the S3 bucket" value = aws_s3_bucket.my_bucket.arn } output "bucket_domain" { description = "Domain name of the bucket" value = aws_s3_bucket.my_bucket.bucket_domain_name } # After apply, view outputs: # terraform output # terraform output bucket_name

Terraform Workflow

┌─────────────────────────────────────────────┐ │ terraform init │ │ • Downloads provider plugins │ │ • Initializes backend │ │ • Creates .terraform directory │ └─────────────────┬───────────────────────────┘ ▼ ┌─────────────────────────────────────────────┐ │ terraform plan │ │ • Reads current state │ │ • Compares with configuration │ │ • Shows what will change │ │ • Does NOT make any changes │ └─────────────────┬───────────────────────────┘ ▼ ┌─────────────────────────────────────────────┐ │ terraform apply │ │ • Executes the plan │ │ • Creates/updates/deletes resources │ │ • Updates state file │ └─────────────────┬───────────────────────────┘ ▼ ┌─────────────────────────────────────────────┐ │ terraform destroy │ │ • Removes all managed resources │ │ • Use when done to avoid charges │ └─────────────────────────────────────────────┘

🔬 Hands-on Lab (2.5 Hours)

Lab 1: Create S3 Bucket with Variables

# Create project structure mkdir -p ~/terraform-labs/lab2-s3 cd ~/terraform-labs/lab2-s3 # providers.tf cat > providers.tf << 'EOF' terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = var.region } EOF # variables.tf cat > variables.tf << 'EOF' variable "region" { description = "AWS region" type = string default = "us-east-1" } variable "bucket_prefix" { description = "Prefix for bucket name" type = string default = "my-terraform" } variable "environment" { description = "Environment name" type = string default = "dev" } EOF # main.tf cat > main.tf << 'EOF' resource "aws_s3_bucket" "demo" { bucket = "${var.bucket_prefix}-${var.environment}-${random_id.suffix.hex}" tags = { Name = "Demo Bucket" Environment = var.environment ManagedBy = "Terraform" } } resource "random_id" "suffix" { byte_length = 4 } resource "aws_s3_bucket_versioning" "demo" { bucket = aws_s3_bucket.demo.id versioning_configuration { status = "Enabled" } } EOF # outputs.tf cat > outputs.tf << 'EOF' output "bucket_name" { value = aws_s3_bucket.demo.id } output "bucket_arn" { value = aws_s3_bucket.demo.arn } output "bucket_region" { value = aws_s3_bucket.demo.region } EOF

Lab 2: Run Terraform Commands

# Initialize - download providers terraform init # Validate configuration terraform validate # Format code (auto-fix formatting) terraform fmt # Plan - see what will be created terraform plan # Apply - create resources terraform apply # Type 'yes' when prompted # View outputs terraform output terraform output bucket_name # View state terraform state list terraform state show aws_s3_bucket.demo # Destroy when done (save money!) terraform destroy

Lab 3: Using tfvars Files

# Create different environments cat > dev.tfvars << 'EOF' region = "us-east-1" environment = "dev" bucket_prefix = "myapp" EOF cat > prod.tfvars << 'EOF' region = "us-west-2" environment = "prod" bucket_prefix = "myapp" EOF # Apply with specific tfvars terraform plan -var-file="dev.tfvars" terraform apply -var-file="dev.tfvars" # Or for production terraform plan -var-file="prod.tfvars"

✅ Day 2 Checklist

  • Understand providers and how to configure them
  • Can create and reference resources
  • Know how to use variables and outputs
  • Master init, plan, apply, destroy workflow
  • Created S3 bucket with Terraform