Terraform on AWS: A Complete Beginner's Guide
A beginner-friendly Terraform AWS guide with provider setup, S3 bucket, EC2 instance, VPC networking, remote state, and best practices for safe deployments.
Terraform
Use Packer and Terraform together to build custom AMIs and deploy them. Golden image pipeline, HCP Packer integration, and automated image lifecycle.
Build custom AMIs with Packer, then deploy them with Terraform:
# 1. Build AMI with Packer
packer build template.pkr.hcl
# 2. Deploy with Terraform (uses latest AMI)
terraform apply# image.pkr.hcl
packer {
required_plugins {
amazon = {
version = ">= 1.2.0"
source = "github.com/hashicorp/amazon"
}
}
}
source "amazon-ebs" "ubuntu" {
ami_name = "myapp-{{timestamp}}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
virtualization-type = "hvm"
root-device-type = "ebs"
}
owners = ["099720109477"]
most_recent = true
}
ssh_username = "ubuntu"
tags = {
Name = "myapp"
Environment = "production"
Builder = "packer"
}
}
build {
sources = ["source.amazon-ebs.ubuntu"]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx nodejs npm",
"sudo systemctl enable nginx",
]
}
provisioner "file" {
source = "app/"
destination = "/tmp/app"
}
provisioner "shell" {
inline = [
"sudo mv /tmp/app /opt/app",
"cd /opt/app && sudo npm install --production",
]
}
}# Look up the latest Packer-built AMI
data "aws_ami" "app" {
most_recent = true
owners = ["self"]
filter {
name = "name"
values = ["myapp-*"]
}
filter {
name = "tag:Builder"
values = ["packer"]
}
}
resource "aws_launch_template" "app" {
name_prefix = "myapp-"
image_id = data.aws_ami.app.id
instance_type = var.instance_type
network_interfaces {
security_groups = [aws_security_group.app.id]
}
tag_specifications {
resource_type = "instance"
tags = {
Name = "myapp"
AMI = data.aws_ami.app.id
AMIName = data.aws_ami.app.name
}
}
}
resource "aws_autoscaling_group" "app" {
desired_capacity = 2
max_size = 4
min_size = 1
vpc_zone_identifier = aws_subnet.private[*].id
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
instance_refresh {
strategy = "Rolling"
preferences {
min_healthy_percentage = 50
}
}
}# GitHub Actions
jobs:
build-ami:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-packer@main
- run: packer init image.pkr.hcl
- run: packer build image.pkr.hcl
deploy:
needs: build-ami
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform apply -auto-approve
# data.aws_ami.app automatically picks up the new AMISource AMI (Ubuntu) → Packer Build → Custom AMI → Terraform Deploy
│ │ │ │
└─ Base OS Install deps Tagged/versioned ASG rolling
Config app Scanned update
Harden OS TestedPacker builds immutable machine images; Terraform deploys them. Use aws_ami data source with owners = ["self"] to auto-discover the latest Packer-built AMI. Combine with ASG instance refresh for zero-downtime rolling deployments. Tag AMIs with Builder = "packer" for easy filtering.
A beginner-friendly Terraform AWS guide with provider setup, S3 bucket, EC2 instance, VPC networking, remote state, and best practices for safe deployments.
Encountering the Inconsistent Dependency Lock File error in Terraform? This guide explains the causes and provides step-by-step solutions to resolve the.
Use the Terraform archive provider to create ZIP files for Lambda functions, Cloud Functions, and deployments. archive_file data source with source_dir and...
Automate Terraform with Azure DevOps Pipelines. YAML pipelines, service connections, environment approvals, and Azure backend state configuration.