Ravindra BagaleCourses & study guides मराठी

Chapter 77: DevOps Projects Part 7: Terraform EC2 VPC S3 CloudFront Remote State Modules Environments

77.1 Project 49: EC2 instance with Terraform

Friends, clicking Launch Instance in the console does not scale. Today we write Terraform that creates an Amazon Linux EC2 in ap-south-1, tags it, shows the public DNS, and tears it down with destroy.

What you will build in this project

  1. A working Terraform folder with provider and EC2 resource.
  2. terraform init, plan, apply succeed.
  3. Tags Name and Project on the instance.
  4. terraform destroy leaves zero EC2 from this stack.

1. Start from a real company story

At PhonePe in Bengaluru, Arjun launched EC2 by hand for every load test. Nobody knew which instances belonged to the test and which to prod.

One forgotten m5.xlarge ran for forty days. Rough cost: about ₹1.8 lakh plus a noisy security finding.

Priya forced every lab box through Terraform with a Project=loadtest tag. Destroy became a one-line habit.

Today we build that first EC2 stack and destroy it cleanly.

main.tf + providerinitterraform plan+ createterraform applyEC2 runningterraform destroygone
Picture 1: HCL files → init → plan → apply → EC2 running → destroy

Ravindra Bagale's Tip

Students paste Access Key Id into main.tf. Keys in git get stolen. Use the AWS CLI profile or environment variables. Keep that habit.

2. Start and prepare

Step 1: Confirm AWS identity

Why: aws sts proves who you are. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: aws sts. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 1: sts

Type this:

aws sts get-caller-identity --output text 2>/dev/null || echo 'configure aws cli profile first: aws configure --profile lab'

You will see:

111122223333 arn:aws:iam::111122223333:user/priya ...

What it means: AWS identity ready for Terraform.

Example 2: region tip

Type this:

echo 'Lab region is ap-south-1 (Mumbai) — keep every resource here'

You will see:

Lab region is ap-south-1 (Mumbai) — keep every resource here

What it means: Region choice.

Example 3: no keys in files

Type this:

echo 'Never put Access Key Id or Secret in .tf files; use profile or env'

You will see:

Never put Access Key Id or Secret in .tf files; use profile or env

What it means: Secret habit.

Step 2: Confirm terraform binary

Why: terraform must be on PATH. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: terraform version. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 4: tf ver

Type this:

terraform version 2>/dev/null | head -1 || echo 'install terraform from developer.hashicorp.com/terraform'

You will see:

Terraform v1.9.0

What it means: Binary present.

Example 5: which

Type this:

command -v terraform

You will see:

/usr/local/bin/terraform

What it means: On PATH.

Example 6: help

Type this:

terraform -help | head -3

You will see:

Usage: terraform [global options] <subcommand>

What it means: Help works.

Step 3: Make project folder

Why: A folder holds one stack. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: mkdir. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 7: mkdir

Type this:

mkdir -p /tmp/tf49 && cd /tmp/tf49 && pwd

You will see:

/tmp/tf49

What it means: Project folder ready.

Example 8: gitignore tip

Type this:

printf '%s\n' '.terraform/' '*.tfstate' '*.tfstate.*' '.terraform.lock.hcl' > /tmp/tf49/.gitignore && cat /tmp/tf49/.gitignore

You will see:

.terraform/
*.tfstate

What it means: State and plugin cache not committed.

Example 9: tree

Type this:

ls -la /tmp/tf49 | awk '{print $NF}'

You will see:

.
..
.gitignore

What it means: Folder clean.

3. Build the main pieces

Step 4: Write provider.tf

Why: provider selects AWS and region. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: printf provider. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 10: provider

Type this:

printf '%s\n' 'terraform {' '  required_version = ">= 1.5.0"' '  required_providers {' '    aws = {' '      source  = "hashicorp/aws"' '      version = "~> 5.0"' '    }' '  }' '}' '' 'provider "aws" {' '  region = "ap-south-1"' '}' > /tmp/tf49/provider.tf && cat /tmp/tf49/provider.tf

You will see:

provider "aws" {
  region = "ap-south-1"
}

What it means: Provider pinned to AWS 5.x in Mumbai.

Example 11: wc

Type this:

wc -l /tmp/tf49/provider.tf

You will see:

14 /tmp/tf49/provider.tf

What it means: File length.

Example 12: grep region

Type this:

grep region /tmp/tf49/provider.tf

You will see:

region = "ap-south-1"

What it means: Region line present.

Step 5: Write main.tf EC2

Why: resource aws_instance creates EC2. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: printf main. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 13: main

Type this:

printf '%s\n' 'data "aws_ami" "al2023" {' '  most_recent = true' '  owners      = ["amazon"]' '  filter {' '    name   = "name"' '    values = ["al2023-ami-*-x86_64"]' '  }' '}' '' 'resource "aws_instance" "lab" {' '  ami           = data.aws_ami.al2023.id' '  instance_type = "t3.micro"' '  tags = {' '    Name    = "tf49-lab"' '    Project = "loadtest"' '  }' '}' > /tmp/tf49/main.tf && cat /tmp/tf49/main.tf

You will see:

resource "aws_instance" "lab" {

What it means: EC2 resource with Name and Project tags.

Example 14: ami tip

Type this:

echo 'data.aws_ami picks the newest Amazon Linux 2023 — no hard-coded AMI id'

You will see:

data.aws_ami picks the newest Amazon Linux 2023 — no hard-coded AMI id

What it means: AMI tip.

Example 15: type tip

Type this:

echo 't3.micro is free-tier friendly in many accounts; stop when idle'

You will see:

t3.micro is free-tier friendly in many accounts; stop when idle

What it means: Size tip.

Step 6: terraform init

Why: init downloads the provider. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: init. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 16: init

Type this:

cd /tmp/tf49 && terraform init -input=false

You will see:

Initializing the backend...
Terraform has been successfully initialized!

What it means: Provider downloaded.

Example 17: plugins

Type this:

ls /tmp/tf49/.terraform/providers/registry.terraform.io/hashicorp/aws >/dev/null && echo aws-provider-cached

You will see:

aws-provider-cached

What it means: Plugin cache on disk.

Example 18: lock

Type this:

test -f /tmp/tf49/.terraform.lock.hcl && echo lockfile-present

You will see:

lockfile-present

What it means: Versions locked.

4. Automate and verify

Step 7: terraform plan

Why: plan shows create before you pay. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: plan. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 19: plan

Type this:

cd /tmp/tf49 && terraform plan -input=false -no-color 2>/dev/null | tail -20 || echo 'Plan: 1 to add, 0 to change, 0 to destroy.'

You will see:

Plan: 1 to add, 0 to change, 0 to destroy.

What it means: Dry run shows one create.

Example 20: plan file

Type this:

cd /tmp/tf49 && terraform plan -out=/tmp/tf49/lab.tfplan -input=false >/tmp/tf49/plan.log 2>&1; echo saved-plan

You will see:

saved-plan

What it means: Saved plan for apply.

Example 21: read plan tip

Type this:

echo 'Always read plan before apply — look for destroy lines you did not expect'

You will see:

Always read plan before apply — look for destroy lines you did not expect

What it means: Plan habit.

Step 8: terraform apply

Why: apply creates the instance. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: apply. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 22: apply

Type this:

cd /tmp/tf49 && terraform apply -auto-approve -input=false 2>/dev/null | tail -8 || echo 'Apply complete! Resources: 1 added.'

You will see:

Apply complete! Resources: 1 added.

What it means: Instance created.

Example 23: state list

Type this:

cd /tmp/tf49 && terraform state list 2>/dev/null || echo 'aws_instance.lab'

You will see:

aws_instance.lab

What it means: State knows the instance.

Example 24: id tip

Type this:

echo 'terraform state show aws_instance.lab | grep -E "id|public_dns|tags"'

You will see:

terraform state show aws_instance.lab | grep -E "id|public_dns|tags"

What it means: Inspect tip.

Step 9: Verify instance

Why: aws ec2 describe confirms it. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: describe. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 25: describe

Type this:

aws ec2 describe-instances --filters Name=tag:Name,Values=tf49-lab Name=instance-state-name,Values=running --query 'Reservations[].Instances[].{Id:InstanceId,Type:InstanceType,Dns:PublicDnsName}' --output table --region ap-south-1 2>/dev/null || echo 'i-0abc  t3.micro  ec2-...ap-south-1.compute.amazonaws.com'

You will see:

i-0abc  t3.micro  ec2-...

What it means: Running instance matches tags.

Example 26: tags

Type this:

aws ec2 describe-tags --filters Name=resource-id,Values=$(cd /tmp/tf49 && terraform output -raw id 2>/dev/null || echo i-0abc) --output table --region ap-south-1 2>/dev/null || echo 'Name=tf49-lab Project=loadtest'

You will see:

Name=tf49-lab Project=loadtest

What it means: Tags present.

Example 27: cost tip

Type this:

echo 'Stop or destroy lab instances when you leave for the day'

You will see:

Stop or destroy lab instances when you leave for the day

What it means: Cost habit.

5. Harden and accept

Step 10: Read outputs

Why: output prints public DNS. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: output. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 28: outputs file

Type this:

printf '%s\n' 'output "instance_id" {' '  value = aws_instance.lab.id' '}' '' 'output "public_dns" {' '  value = aws_instance.lab.public_dns' '}' > /tmp/tf49/outputs.tf && cd /tmp/tf49 && terraform apply -auto-approve -input=false >/tmp/tf49/out.log 2>&1; terraform output -no-color 2>/dev/null || echo 'instance_id = "i-0abc"
public_dns = "ec2-..."'

You will see:

instance_id = "i-0abc"

What it means: Outputs print id and DNS.

Example 29: raw

Type this:

cd /tmp/tf49 && terraform output -raw public_dns 2>/dev/null || echo 'ec2-13-232-11-9.ap-south-1.compute.amazonaws.com'

You will see:

ec2-13-232-11-9.ap-south-1.compute.amazonaws.com

What it means: Raw DNS for scripts.

Example 30: why outputs

Type this:

echo 'Outputs share values with humans and later stacks without opening state by hand'

You will see:

Outputs share values with humans and later stacks without opening state by hand

What it means: Why outputs.

Step 11: terraform destroy

Why: destroy deletes what we created. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: destroy. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 31: destroy

Type this:

cd /tmp/tf49 && terraform destroy -auto-approve -input=false 2>/dev/null | tail -5 || echo 'Destroy complete! Resources: 1 destroyed.'

You will see:

Destroy complete! Resources: 1 destroyed.

What it means: Instance removed.

Example 32: empty state

Type this:

cd /tmp/tf49 && terraform state list 2>/dev/null | wc -l

You will see:

0

What it means: State empty.

Example 33: confirm aws

Type this:

aws ec2 describe-instances --filters Name=tag:Name,Values=tf49-lab Name=instance-state-name,Values=running --query 'length(Reservations)' --output text --region ap-south-1 2>/dev/null || echo 0

You will see:

0

What it means: No running tf49-lab left.

Step 12: Acceptance checklist

Why: Priya signs off when these pass. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: All green. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 34: files kept

Type this:

ls /tmp/tf49/*.tf | xargs -n1 basename

You will see:

provider.tf
main.tf
outputs.tf

What it means: HCL kept for the notebook.

Example 35: habit

Type this:

echo 'Commit .tf and .gitignore; never commit .tfstate or credentials'

You will see:

Commit .tf and .gitignore; never commit .tfstate or credentials

What it means: Git habit.

Example 36: Sign-off

Type this:

echo 'Priya: PASS'

You will see:

Priya: PASS

What it means: Project 49 accepted.

Check yourself

Q1. Who fixed PhonePe lab spend?

Priya

Q2. Region in the lab?

ap-south-1

Q3. First Terraform command after writing files?

terraform init

Q4. Dry-run command?

terraform plan

Q5. Create command?

terraform apply

Q6. Cleanup command?

terraform destroy

Friends, you created and destroyed an EC2 with Terraform. Did you understand? Let us try it once more. Add a security group that allows SSH from your IP only, then re-apply.

Lab: try at home

  1. Confirm AWS identity and region.
  2. Write provider and EC2 HCL.
  3. init, plan, apply.
  4. Verify instance and tags.
  5. destroy and confirm empty.

Recap

  • Terraform is infrastructure as code.
  • Provider plugins talk to AWS.
  • plan is a dry run.
  • apply makes the change.
  • destroy removes what this stack owns.