- Understand Terraform workspaces for environment management.
- Learn how to use data sources to query existing infrastructure.
- Understand provisioners and when to use them.
- Practice with workspaces, data sources, and provisioners through hands-on examples.
Concept:
Workspaces in Terraform allow you to use the same configuration for multiple environments (like dev, stage, and prod) without duplicating code. Each workspace maintains its own state file, meaning the same config can manage separate resources across different environments.
Commands:
terraform workspace new dev
terraform workspace new prod
terraform workspace list
terraform workspace select devExample:
resource "aws_s3_bucket" "demo" {
bucket = "demo-${terraform.workspace}-bucket"
}When applied in each workspace:
dev→ createsdemo-dev-bucketprod→ createsdemo-prod-bucket
Best Practice:
Use workspaces for small environment differences. For major variations, use separate folders or repos.
Concept:
Data sources allow Terraform to query existing resources and reuse their attributes in your configuration. This is helpful when you want to reference infrastructure not managed by your Terraform code.
Example:
data "aws_vpc" "default" {
default = true
}
data "aws_subnet_ids" "default" {
vpc_id = data.aws_vpc.default.id
}
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical (Ubuntu)
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-*-amd64-server-*"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
subnet_id = data.aws_subnet_ids.default.ids[0]
}Key Point:
Data sources are read-only and will not alter or destroy the referenced resources.
Concept:
Provisioners let you execute scripts or commands after a resource is created. They are often used to perform initial setup tasks such as configuration, file transfers, or installing software.
Types of Provisioners:
- local-exec: Runs on the local machine executing Terraform.
- remote-exec: Runs commands on the remote resource via SSH or WinRM.
Example: local-exec
resource "aws_instance" "example" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
provisioner "local-exec" {
command = "echo ${self.public_ip} >> public_ips.txt"
}
}Example: remote-exec
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
key_name = "terraform-key"
provisioner "remote-exec" {
inline = [
"sudo apt-get update -y",
"sudo apt-get install nginx -y"
]
}
connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/terraform-key.pem")
host = self.public_ip
}
}Best Practice:
Use provisioners sparingly and only when other options (like user_data, cloud-init, or configuration management tools such as Ansible) are not practical.
terraform import is your lifeline when:
- A resource already exists in the cloud
- You want Terraform to manage it going forward
- Without recreating it
- Zero downtime
- Write the full resource block in your config first
- Then run the import command:
terraform import aws_s3_bucket.demo mybucketAfter import – reality check
State now knows everything about the real resource Your config must still match reality (attributes, tags, etc.) You’ll likely need to manually clean up/fix the config afterward
Memory Trick (never forget this!) Import moves: Real world → State file Import does NOT generate or fix your config! This is the #1 thing juniors get wrong — import is NOT magic code-generation.
- Create two workspaces:
terraform workspace new dev terraform workspace new prod
- Deploy an EC2 instance using a data source to fetch the latest Ubuntu AMI.
- Add a local-exec provisioner to log the instance’s public IP into a text file.
- Switch between
devandprodworkspaces to confirm each maintains its own instance and state. - Clean up resources when done:
terraform destroy
- Workspaces: Isolate environments with unique state files.
- Data sources: Read attributes of existing infrastructure.
- Provisioners: Run setup scripts during resource creation or destruction.
- Import: Bring existing infrastructure under Terraform management (write config first, then import - it moves real world → state, but doesn't generate code).
What happens if you run terraform apply in a new workspace without selecting it first?
A) It applies to the default workspace.
B) It errors out.
C) It creates resources in all workspaces.
D) It creates a new workspace automatically
Show Answer
Answer: **A** - Terraform always operates in the current workspace. If you haven't selected a workspace, it uses the "default" workspace. You must use `terraform workspace select` to switch.What is the main difference between a data source and a resource? A) Data sources are read-only, resources are managed B) Data sources cost money, resources are free C) Data sources only work with AWS, resources work everywhere D) There is no difference
Show Answer
Answer: **A** - Data sources are read-only queries that fetch information about existing infrastructure without managing it. Resources are created, updated, and destroyed by Terraform.When should you use provisioners instead of user_data or cloud-init? A) Always - provisioners are the recommended approach B) When you need to run commands after resource creation that can't be done with user_data C) Never - provisioners should never be used D) Only for Windows instances