DevOps
Terraform Infrastructure as Code Complete Guide
Master Terraform for infrastructure as code with AWS, GCP, Azure, state management, modules, workspaces, and production best practices.
What you'll learn
- Install Terraform and configure cloud provider credentials
- Write HCL resources, variables, and outputs
- Manage remote state with S3 and DynamoDB locking
- Structure reusable modules
- Use workspaces for multi-environment deployments
- Plan, apply, and safely destroy infrastructure
- Integrate Terraform into CI/CD with GitHub Actions
Installation & Setup
Bash
1# Install Terraform on Ubuntu 24.04
2wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor \
3 -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
4echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
5 https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
6 sudo tee /etc/apt/sources.list.d/hashicorp.list
7sudo apt update && sudo apt install -y terraform
8
9terraform version
10
11# Configure AWS credentials
12aws configure
13# Or use environment variables:
14export AWS_ACCESS_KEY_ID=...
15export AWS_SECRET_ACCESS_KEY=...
16export AWS_DEFAULT_REGION=us-east-1HCL Basics
HCL
1# main.tf
2terraform {
3 required_version = ">= 1.6"
4 required_providers {
5 aws = {
6 source = "hashicorp/aws"
7 version = "~> 5.0"
8 }
9 }
10}
11
12provider "aws" {
13 region = var.aws_region
14}
15
16resource "aws_vpc" "main" {
17 cidr_block = var.vpc_cidr
18 enable_dns_hostnames = true
19 tags = merge(local.common_tags, { Name = "${var.project}-vpc" })
20}
21
22resource "aws_instance" "web" {
23 ami = data.aws_ami.ubuntu.id
24 instance_type = var.instance_type
25 subnet_id = aws_subnet.public.id
26 tags = { Name = "${var.project}-web" }
27}
28
29# variables.tf
30variable "aws_region" { default = "us-east-1" }
31variable "project" { type = string }
32variable "vpc_cidr" { default = "10.0.0.0/16" }
33variable "instance_type" { default = "t3.micro" }
34
35# outputs.tf
36output "web_public_ip" { value = aws_instance.web.public_ip }
37
38# locals.tf
39locals {
40 common_tags = {
41 Project = var.project
42 ManagedBy = "terraform"
43 }
44}Remote State
HCL
1# backend.tf — S3 with DynamoDB locking
2terraform {
3 backend "s3" {
4 bucket = "mycompany-terraform-state"
5 key = "production/terraform.tfstate"
6 region = "us-east-1"
7 encrypt = true
8 dynamodb_table = "terraform-state-lock"
9 }
10}
11
12# Create the S3 bucket and DynamoDB table once manually (bootstrap module)
13# Then run:
14terraform init # migrates state to backend
15terraform plan
16terraform applyModules
HCL
1# modules/vpc/main.tf — reusable VPC module
2variable "cidr" {}
3variable "project" {}
4
5resource "aws_vpc" "this" {
6 cidr_block = var.cidr
7 tags = { Name = "${var.project}-vpc" }
8}
9
10output "vpc_id" { value = aws_vpc.this.id }
11output "vpc_cidr" { value = aws_vpc.this.cidr_block }
12
13# Root module usage
14module "vpc" {
15 source = "./modules/vpc"
16 cidr = "10.0.0.0/16"
17 project = var.project
18}
19
20# Or use the Terraform Registry
21module "vpc" {
22 source = "terraform-aws-modules/vpc/aws"
23 version = "~> 5.0"
24 name = var.project
25 cidr = "10.0.0.0/16"
26 azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
27}Workspaces
Bash
1terraform workspace new staging
2terraform workspace new production
3terraform workspace list
4terraform workspace select staging
5
6# Reference workspace in configuration
7resource "aws_instance" "web" {
8 instance_type = terraform.workspace == "production" ? "t3.medium" : "t3.micro"
9}
10
11# Better pattern: separate tfvars per environment
12terraform apply -var-file=environments/staging.tfvars
13terraform apply -var-file=environments/production.tfvarsCI/CD Integration
YAML
1# GitHub Actions — plan on PR, apply on merge to main
2jobs:
3 terraform:
4 runs-on: ubuntu-24.04
5 steps:
6 - uses: actions/checkout@v4
7 - uses: hashicorp/setup-terraform@v3
8 with:
9 terraform_version: "~1.6"
10
11 - run: terraform init
12 env:
13 AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
14 AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
15
16 - run: terraform validate
17 - run: terraform plan -out=tfplan
18
19 - name: Apply (main branch only)
20 if: github.ref == 'refs/heads/main'
21 run: terraform apply tfplan