Back to Cloud & DevOps

Module 6: Infrastructure as Code

Manage and provision infrastructure through code instead of manual processes. Learn Terraform and CloudFormation.

What is Infrastructure as Code (IaC)?

Infrastructure as Code (IaC) means managing your servers, networks, and cloud resources using code files instead of clicking through web consoles or running manual commands. Think of it like having blueprints for a house - instead of telling builders where to put each brick, you give them detailed plans they can follow repeatedly to build identical houses.

With IaC, you write configuration files that describe what infrastructure you want (10 servers, a database, a load balancer), and tools like Terraform or CloudFormation automatically create it for you. If you need to make changes, you update the code and reapply it.

🏗️ Real-World Analogy:

Imagine you're opening a chain of coffee shops:

  • Without IaC: For each new shop, you manually order furniture, hire contractors, set up equipment, and configure everything by hand. Each shop ends up slightly different, and opening a new location takes weeks.
  • With IaC: You create a detailed blueprint once. When opening a new shop, you hand the blueprint to a team, and they build an identical shop in days. Need to change the menu board design? Update the blueprint and apply it to all shops.

Why Use Infrastructure as Code?

🔄 Repeatability

Create identical environments every time. Your development, staging, and production environments are guaranteed to match because they're built from the same code.

📝 Version Control

Track every infrastructure change in Git. Know who changed what, when, and why. Roll back to previous versions if something breaks.

⚡ Speed

Provision entire environments in minutes instead of days. Spin up test environments, run tests, and tear them down automatically.

📚 Documentation

Your infrastructure code IS your documentation. New team members can read the code to understand exactly how everything is configured.

Terraform Basics

Terraform is the most popular IaC tool. It works with AWS, Azure, Google Cloud, and hundreds of other providers. You write configuration files in HCL (HashiCorp Configuration Language), which looks similar to JSON but is easier to read and write.

Your First Terraform Configuration

Let's create an AWS EC2 instance (a virtual server). Create a file called main.tf:

# main.tf

# Configure the AWS provider

provider "aws" {

region = "us-east-1"

}

# Create an EC2 instance

resource "aws_instance" "web_server" {

ami = "ami-0c55b159cbfafe1f0"

instance_type = "t2.micro"

tags = {

Name = "MyWebServer"

}

}

📖 Understanding the Code:

  • provider: Tells Terraform you're using AWS in the us-east-1 region
  • resource: Defines something you want to create (an EC2 instance)
  • ami: The machine image (like a template for the server)
  • instance_type: The size of the server (t2.micro is small and cheap)
  • tags: Labels to help identify your resources

Terraform Workflow

Terraform has a simple three-step workflow:

1. terraform init

Initialize your project. Downloads provider plugins (like the AWS plugin) and sets up the working directory.

$ terraform init

2. terraform plan

Preview what changes Terraform will make. Like a "dry run" - shows you what will be created, modified, or destroyed without actually doing it.

$ terraform plan

3. terraform apply

Apply the changes. Creates, updates, or deletes resources to match your configuration. Asks for confirmation before making changes.

$ terraform apply

Variables and Outputs

Variables make your Terraform code reusable. Instead of hardcoding values, you can parameterize them. Outputs let you extract information from your infrastructure.

Using Variables

Create a variables.tf file:

# variables.tf

variable "instance_type" {

description = "EC2 instance type"

type = string

default = "t2.micro"

}

variable "environment" {

description = "Environment name"

type = string

}

Now use these variables in main.tf:

resource "aws_instance" "web_server" {

ami = "ami-0c55b159cbfafe1f0"

instance_type = var.instance_type

tags = {

Name = "WebServer"

Environment = var.environment

}

}

Defining Outputs

Create an outputs.tf file to extract useful information:

# outputs.tf

output "instance_id" {

description = "ID of the EC2 instance"

value = aws_instance.web_server.id

}

output "public_ip" {

description = "Public IP address"

value = aws_instance.web_server.public_ip

}

After running terraform apply, you'll see these outputs displayed, showing you the instance ID and public IP address.

Terraform State

Terraform keeps track of your infrastructure in a "state file" (terraform.tfstate). This file is like a database that maps your configuration to real-world resources. It knows which EC2 instance in AWS corresponds to which resource in your code.

⚠️ State File Warning:

The state file contains sensitive information (like passwords and IP addresses). Never commit it to Git!

  • • Add *.tfstate to your .gitignore
  • • Use remote state storage (S3, Terraform Cloud) for teams
  • • Enable state locking to prevent conflicts

Remote State with S3

For team collaboration, store state in S3:

# backend.tf

terraform {

backend "s3" {

bucket = "my-terraform-state"

key = "prod/terraform.tfstate"

region = "us-east-1"

encrypt = true

dynamodb_table = "terraform-locks"

}

}

Terraform Modules

Modules are reusable packages of Terraform configuration. Think of them like functions in programming - you write the code once and reuse it multiple times with different inputs. For example, you might create a "web server" module that sets up an EC2 instance, security group, and load balancer, then reuse it for different environments.

Creating a Module

Create a directory structure:

modules/

web-server/

main.tf

variables.tf

outputs.tf

In modules/web-server/main.tf:

resource "aws_instance" "server" {

ami = var.ami

instance_type = var.instance_type

tags = {

Name = var.server_name

}

}

resource "aws_security_group" "web" {

name = "${var.server_name}-sg"

ingress {

from_port = 80

to_port = 80

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"]

}

}

Using a Module

In your root main.tf:

module "prod_server" {

source = "./modules/web-server"

ami = "ami-0c55b159cbfafe1f0"

instance_type = "t2.medium"

server_name = "production-web"

}

module "dev_server" {

source = "./modules/web-server"

ami = "ami-0c55b159cbfafe1f0"

instance_type = "t2.micro"

server_name = "development-web"

}

Now you can create multiple servers with different configurations using the same module!

AWS CloudFormation

CloudFormation is AWS's native IaC tool. While Terraform works with multiple cloud providers, CloudFormation is AWS-only but deeply integrated with AWS services. You write templates in JSON or YAML that describe your AWS resources.

CloudFormation Template

Here's a simple CloudFormation template to create an EC2 instance:

# template.yaml

AWSTemplateFormatVersion: '2010-09-09'

Description: Simple EC2 instance

Parameters:

InstanceType:

Type: String

Default: t2.micro

Description: EC2 instance type

Resources:

WebServer:

Type: AWS::EC2::Instance

Properties:

ImageId: ami-0c55b159cbfafe1f0

InstanceType: !Ref InstanceType

Tags:

- Key: Name

Value: MyWebServer

Outputs:

InstanceId:

Description: Instance ID

Value: !Ref WebServer

PublicIP:

Description: Public IP

Value: !GetAtt WebServer.PublicIp

Deploying with CloudFormation

Use the AWS CLI to create a stack:

$ aws cloudformation create-stack \

--stack-name my-web-server \

--template-body file://template.yaml \

--parameters ParameterKey=InstanceType,ParameterValue=t2.small

🔄 Terraform vs CloudFormation:

Terraform

  • ✓ Multi-cloud (AWS, Azure, GCP)
  • ✓ HCL language (easier to read)
  • ✓ Large community
  • ✗ Requires separate tool

CloudFormation

  • ✓ Native AWS integration
  • ✓ No extra tools needed
  • ✓ AWS support included
  • ✗ AWS-only

🛠️ Hands-On Project: Deploy a Complete Web Application

Let's build a complete infrastructure for a web application using Terraform. We'll create:

  • • VPC with public and private subnets
  • • EC2 instances for web servers
  • • RDS database
  • • Application Load Balancer
  • • Security groups

Complete Terraform Configuration

# main.tf

# VPC

resource "aws_vpc" "main" {

cidr_block = "10.0.0.0/16"

tags = { Name = "main-vpc" }

}

# Public Subnet

resource "aws_subnet" "public" {

vpc_id = aws_vpc.main.id

cidr_block = "10.0.1.0/24"

tags = { Name = "public-subnet" }

}

# Security Group for Web Servers

resource "aws_security_group" "web" {

name = "web-sg"

vpc_id = aws_vpc.main.id

ingress {

from_port = 80

to_port = 80

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"]

}

}

# EC2 Instance

resource "aws_instance" "web" {

count = 2

ami = "ami-0c55b159cbfafe1f0"

instance_type = "t2.micro"

subnet_id = aws_subnet.public.id

vpc_security_group_ids = [aws_security_group.web.id]

tags = {

Name = "web-server-${count.index + 1}"

}

}

# RDS Database

resource "aws_db_instance" "database" {

identifier = "myapp-db"

engine = "postgres"

instance_class = "db.t3.micro"

allocated_storage = 20

username = "admin"

password = var.db_password

skip_final_snapshot = true

}

🎯 What This Creates:

  • • A VPC (Virtual Private Cloud) - your own isolated network
  • • A public subnet - where web servers live
  • • Security group - firewall rules allowing HTTP traffic
  • • 2 EC2 instances - web servers (using count = 2)
  • • RDS database - PostgreSQL database for your app

Best Practices

✅ Do

  • ✓ Use version control for all IaC code
  • ✓ Store state remotely (S3, Terraform Cloud)
  • ✓ Use modules for reusable components
  • ✓ Always run terraform plan before apply
  • ✓ Use variables for environment-specific values
  • ✓ Tag all resources for cost tracking
  • ✓ Document your infrastructure code

❌ Don't

  • ✗ Commit state files to Git
  • ✗ Hardcode secrets in configuration
  • ✗ Make manual changes to managed resources
  • ✗ Skip terraform plan
  • ✗ Use default VPCs in production
  • ✗ Ignore Terraform warnings
  • ✗ Share state files without locking

📚 Module Summary

You've learned how to manage infrastructure as code:

  • ✓ Understanding IaC benefits and concepts
  • ✓ Writing Terraform configurations
  • ✓ Managing state and using remote backends
  • ✓ Creating reusable modules
  • ✓ Working with AWS CloudFormation
  • ✓ Following IaC best practices

Congratulations! You've completed the Cloud & DevOps learning path. You now have the skills to deploy, manage, and automate cloud infrastructure like a pro!