Getting started with Terraform
In this tutorial, we will launch an EC2 instance on AWS using Terraform.
Prerequisites
- AWS Identity Center user account with
AdministratorAccess
permission set. - Linux, Mac, or Windows computer to install Terraform.
Outline
- What is Terraform
- How to set up Terraform CLI for AWS
- How to write Terraform configuration to launch an EC2
- How to provision cloud infrastructure with Terraform CLI
What is Terraform
Terraform is an Infrastructure as Code (IaC) tool developed by HashiCorp.
An IaC tool automates cloud infrastructure provisioning. Without an IaC tool, you will be creating cloud resources manually via CLI or the cloud provider’s GUI. Manual provisioning is not scalable. Imagine creating hundreds of EC2 instances manually.
An IaC tool allows you to describe cloud infrastructure as human-readable text. The tool will interpret the text and provision the required resources in the cloud.
Terraform is one of the many IaC tools in the market.
You can either install Terraform on your computer or use the Terraform SAAS solution.
In this tutorial, we are going to use the locally installed version of Terraform.
How to set up Terraform CLI for AWS
Install Terraform by following the installation instructions for your platform.
Verify the installation.
terraform version
Terraform v1.7.1
on linux_arm64
Note that your version could be newer than this.
Configure AWS credentials for Terraform
Terraform requires that you have the AWS CLI locally installed and configured. Follow these instructions to set up the AWS CLI, if you have not already done so.
After you have configured the AWS CLI, you must set the AWS credentials in the environment variables for Terraform to authenticate with AWS.
Log in to your AWS Access Portal URL you get in the AWS IAM Identity Center. Click on the AWS Account and click on the Command line or programmatic access
link.
You will get this dialog box.
Set the environment variables (Option-1) AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, and AWS_SESSION_TOKEN
according to the instructions for your platform.
How to write Terraform configuration to launch an EC2
A Terraform configuration is a definition of cloud resources written in Terraform language. Terraform language is based on HCL (HashiCorp Configuration Language). The Terraform language syntax resembles JSON but is not exactly equal to JSON.
This is a sample of a Terraform configuration that describes a subnet on AWS.
resource "aws_subnet" "subnet-1" {
cidr_block = "10.10.0.0/24"
vpc_id = "xxx"
availability_zone = "us-west-2a"
}
Terraform configuration is declarative. It does not specify the instructions for provisioning cloud resources but defines the final state of the resources to be provisioned.
Create a new Terraform configuration
In the working directory create file main.tf
with the following content.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "us-west-2"
}
The name main
is just a convention. You can use any name you like.
Terraform language has two main types of syntax.
-
Blocks enclosed by a pair of curly braces. A block is a container for other blocks and arguments. A block has an optional type and a set of labels.
-
Arguments that assign a values to a names.
Our main.tf
has two blocks; terraform
and provider
.
The terraform
block has one argument and one block.
The provider
block has one argument that configures the AWS region
.
Terraform uses providers
for provisioning resources on different cloud services. We use the aws
provider in this tutorial. Terraform has providers for many cloud infrastructure and cloud services.
Let’s add these three resource
blocks to the main.tf
to define an AWS VPC, a subnet, and an EC2 instance.
resource "aws_vpc" "vpc-1" {
cidr_block = "10.10.0.0/16"
}
resource "aws_subnet" "subnet-1" {
cidr_block = "10.10.0.0/24"
vpc_id = aws_vpc.vpc-1.id
availability_zone = "us-west-2a"
}
resource "aws_instance" "my_server" {
ami = "ami-008fe2fc65df48dac"
instance_type = "t2.micro"
subnet_id = aws_subnet.subnet-1.id
}
A resource
block has a type that defines the type of AWS resource and a label that specifies the name.
Most of the arguments inside these three blocks explain themselves. But, two deserve attention.
-
vpc_id
- Thevpc_id
in theaws_subnet
block refers to the ID of the VPC created in theaws_vpc
resource block. We refer to this ID asresource_type.name.id
. Similarly, we refer to the Subnet ID inside theaws_instance
resource block. -
ami
- Theami
in theaws_instance
block refers to an Amazon Machine Image (AMI) ID which is a binary image of an OS for launching an EC2 instance. AWS maintains AMIs for popular operating systems like RedHat, Ubuntu, and Windows. For this tutorial, we’ll use an Ubuntu AMI.
Finding an AMI ID
You need an AMI ID that’s available in the region where you are launching the EC2.
Log in to the AWS console and choose the region. Select EC2 from the Services menu. From the left navigation menu select AMI Catalog
in Images
. Enter ubuntu
in the search box to find the Ubuntu AMIs.
Copy the AMI ID in the latest Ubuntu OS version and use it as the value in the ami
argument.
Now, we have a complete Terraform configuration for launching an EC2.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "us-west-2"
}
resource "aws_vpc" "vpc-1" {
cidr_block = "10.10.0.0/16"
}
resource "aws_subnet" "subnet-1" {
cidr_block = "10.10.0.0/24"
vpc_id = aws_vpc.vpc-1.id
availability_zone = "us-west-2a"
}
resource "aws_instance" "my_server" {
ami = "ami-008fe2fc65df48dac"
instance_type = "t2.micro"
subnet_id = aws_subnet.subnet-1.id
}
This configuration is in a single file. But, Terraform configurations can span across multiple files.
How to provision cloud infrastructure with Terraform CLI
Initialize
The init
command installs the providers defined in the Terraform configuration.
terraform init
Terraform installs the providers inside the .terraform
directory in the current path. So you must run the init
command again when working on a new path.
Format the configuration file
Formatting is not mandatory but highly recommended for readability.
terraform fmt
After running fmt
, open the file in a text editor to see how Terraform has improved readability.
Validate the configuration file
Validate the configuration file for syntax errors.
terraform validate
Success! The configuration is valid.
Terraform will prompt syntax errors if there are any. Correct them and validate, until you get the success message.
Apply the configuration
The apply
command provisions the cloud resources.
terraform apply
Terraform identifies the resources to be created or deleted and prompts a confirmation before making the changes.
Type yes
and Terraform will continue to create or delete the resources.
If the AWS credentials are not properly configured, or if you do not have the privilege to provision specific cloud resources, you will get an error at this stage.
Check the state
When you run the apply
command Terraform creates the file terraform.tfstate
in the working directory to store the status of the resources created.
The state
CLI command uses this file to query the status of the cloud resources.
List all resources created.
terraform state list
Check the parameters of a specific resource.
terraform state show aws_instance.my_server
Update cloud resources
To update the provisioned cloud resources we just have to update the configuration file and rerun the apply
command. Terraform takes care of adding or deleting the cloud resources according to the updated configuration files.
Let’s update main.tf
to create a new subnet subnet-2
and change the EC2 instance to attach to subnet-2
instead of subnet-1
.
resource "aws_subnet" "subnet-2" {
cidr_block = "10.10.1.0/24"
vpc_id = aws_vpc.vpc-1.id
availability_zone = "us-west-2a"
}
resource "aws_instance" "my_server" {
ami = "ami-008fe2fc65df48dac"
instance_type = "t2.micro"
subnet_id = aws_subnet.subnet-2.id
}
Here’s the updated main.tf
file.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "us-west-2"
}
resource "aws_vpc" "vpc-1" {
cidr_block = "10.10.0.0/16"
}
resource "aws_subnet" "subnet-1" {
cidr_block = "10.10.0.0/24"
vpc_id = aws_vpc.vpc-1.id
availability_zone = "us-west-2a"
}
resource "aws_subnet" "subnet-2" {
cidr_block = "10.10.1.0/24"
vpc_id = aws_vpc.vpc-1.id
availability_zone = "us-west-2a"
}
resource "aws_instance" "my_server" {
ami = "ami-008fe2fc65df48dac"
instance_type = "t2.micro"
subnet_id = aws_subnet.subnet-2.id
}
Apply the configuration.
terraform apply
Terraform considers the cloud resource as immutable. So, instead of changing the EC2 instance, Terraform deletes the existing EC2 instance and launches a new instance connected to the subnet subnet-2
.
Delete the cloud resources
Use the destroy
command to delete the cloud resources.
terraform destroy
Type in yes
to confirm and Terraform will delete all the resources created from this configuration file. Terraform will use the terraform.tfstate
file to find the resource IDs that need to be deleted.
Check the state again.
terraform state list
The output should be blank.
Wrapping up
In this tutorial, we used Terraform to provision a simple cloud setup on AWS.
You will appreciate that the IaC approach with Terraform is much faster and easier than provisioning resources via GUI when you have to create a large number of cloud resources.
When updating a cloud setup, Terraform treats the EC2 instances as immutable. For any change in an EC2 instance, Terraform deletes and recreates a new EC2. Make note of this behavior as your application needs to be stateless to take advantage of IaC.
Stay tuned as we bring more tutorials on AWS.