Terraform Level 1, Task 10: Data Protection with EBS Snapshots¶
Today's task was a critical lesson in data protection and disaster recovery in the cloud. My objective was to create an EBS Snapshot from an existing EBS Volume using Terraform. This is the standard way to create backups of your server's disks in AWS.
This exercise was particularly insightful because it required me to update an existing Terraform configuration and understand how Terraform manages dependencies between resources. It also exposed me to a more complex provider.tf file, which taught me about how Terraform can be configured for non-standard environments like a lab that simulates AWS locally. This document is my very detailed, first-person guide to that entire process.
Table of Contents¶
- The Task
- My Step-by-Step Solution
- Why Did I Do This? (The "What & Why")
- Deep Dive: A Line-by-Line Explanation of the Terraform Files
- Common Pitfalls
- Exploring the Commands I Used
The Task¶
My objective was to use Terraform to create a snapshot of an existing EBS volume named nautilus-vol. The requirements were:
1. The new snapshot's name tag had to be nautilus-vol-ss.
2. It needed a specific description: Nautilus Snapshot.
3. The snapshot had to be in a completed state.
4. All the code had to be in a single main.tf file.
My Step-by-Step Solution¶
The process involved updating an existing Terraform file to add the new snapshot resource and then running the standard three-step workflow.
Phase 1: Writing the Code¶
In the /home/bob/terraform directory, I opened the existing main.tf file, which already defined the source EBS volume. I added a new resource block to the end of the file.
# This is the new resource block I added to the main.tf file.
resource "aws_ebs_snapshot" "nautilus_vol_snapshot" {
volume_id = aws_ebs_volume.k8s_volume.id
description = "Nautilus Snapshot"
tags = {
Name = "nautilus-vol-ss"
}
}
provider.tf file at all, as it was already correctly configured.
Phase 2: The Terraform Workflow¶
From my terminal in the same directory, I executed the three core commands.
-
Initialize: This ensured my provider plugins were up to date.
terraform init -
Plan: The "dry run" output showed that Terraform intended to create both the
aws_ebs_volumeand theaws_ebs_snapshotthat depends on it.terraform plan -
Apply: This command executed the plan. After I confirmed with
yes, Terraform first created the EBS volume and then immediately started creating the snapshot. Creating a snapshot takes time, and Terraform patiently waited for the process to finish and for the snapshot to become "completed" before reporting the final success message:Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Why Did I Do This? (The "What & Why")¶
- EBS Snapshot: I learned to think of a snapshot as a point-in-time backup of an EBS volume. This backup is stored durably and cost-effectively in Amazon S3 (though this happens behind the scenes).
- Data Protection & Disaster Recovery: This is the primary reason for snapshots.
- Backup: If data on my volume is accidentally deleted or corrupted, I can create a brand new volume from the snapshot to restore the data to its previous state.
- Disaster Recovery: I can copy snapshots to other AWS regions. If the us-east-1 region were to have a major outage, I could restore my volume from the copied snapshot in a different region (like us-west-2) and get my application back online.
- Incremental Backups: The first snapshot of a volume is a full copy. However, subsequent snapshots are incremental. This means they only save the blocks on the disk that have changed since the last snapshot. This is incredibly efficient and saves a lot of money on storage costs.
- Terraform Implicit Dependency: This was a key concept. My aws_ebs_snapshot resource needed the ID of the volume to snapshot. By referencing the ID of the aws_ebs_volume resource (aws_ebs_volume.k8s_volume.id), I created an "implicit dependency." Terraform is smart enough to see this link, and it automatically knows it must create the volume before it can create the snapshot.
Deep Dive: A Line-by-Line Explanation of the Terraform Files¶
This task involved two files. Understanding both was key.
The provider.tf File (The Lab Environment Setup)¶
This file was unusual and taught me a lot about how lab environments can work.
# The terraform block is for core settings.
terraform {
# This section declares which providers my code needs and, optionally,
# which versions. This helps ensure my code is run with a compatible
# version of the provider plugin.
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.91.0"
}
}
}
# The provider block configures a specific provider.
provider "aws" {
region = "us-east-1"
# These next lines are NOT standard for a real AWS account.
# They are used for lab environments that use a local AWS simulator
# like LocalStack.
skip_credentials_validation = true
skip_requesting_account_id = true
s3_use_path_style = true
# The 'endpoints' block is the biggest clue. It redirects all AWS API
# calls from their normal internet addresses to a local service
# running at 'http://aws:4566'. This is how the lab can simulate
# AWS without needing real credentials.
endpoints {
ec2 = "http://aws:4566"
# ... and many other services
}
}
The main.tf File (My Solution)¶
This file defined the actual infrastructure I was building.
[Image of an EBS snapshot being created from a volume]
# This is the existing resource block that defines the source EBS volume.
# I named it "k8s_volume" locally within my Terraform code.
resource "aws_ebs_volume" "k8s_volume" {
availability_zone = "us-east-1a"
size = 5
type = "gp2"
tags = {
Name = "nautilus-vol"
}
}
# This is the new resource block I added to create the snapshot.
# I named it "nautilus_vol_snapshot" locally.
resource "aws_ebs_snapshot" "nautilus_vol_snapshot" {
# This is the most important line: The Dependency Link.
# I am telling this resource that its 'volume_id' is the 'id' attribute
# from the 'aws_ebs_volume' resource named 'k8s_volume'.
# Terraform sees this and builds the resources in the correct order.
volume_id = aws_ebs_volume.k8s_volume.id
# A helpful description for the snapshot.
description = "Nautilus Snapshot"
# Standard tagging to give the snapshot a recognizable name.
tags = {
Name = "nautilus-vol-ss"
}
}
Common Pitfalls¶
- Forgetting terraform destroy: Snapshots, like EBS volumes, cost money. It's crucial to delete any snapshots you no longer need to avoid unnecessary charges.
- Snapshot Creation Time: Creating a snapshot is not instant, especially for large volumes. When running terraform apply, it's important to be patient. Terraform will wait for the snapshot status to become "completed" before it finishes.
- Incorrectly Referencing the Volume ID: If I had a typo in the dependency link (aws_ebs_volume.k8s_volume.id), Terraform would have failed during the plan phase because it couldn't find the referenced resource.
Exploring the Commands I Used¶
The workflow was the standard, three-step Terraform process:
- terraform init: Prepared my working directory by downloading the aws provider plugin.
- terraform plan: Read my code, detected the implicit dependency, and showed me a correct plan to create the volume first, followed by the snapshot.
- terraform apply: Executed the plan. It built the volume, then created the snapshot, all in the correct order, after I confirmed with yes.