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.
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.
3. terraform apply
Apply the changes. Creates, updates, or deletes resources to match your configuration. Asks for confirmation before making changes.
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
*.tfstateto 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 planbefore 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!