Terraform With AWS
Terraform is an Infrastructure as a Code tool that allows you to create and improve infrastructure. Learn how to spin up Terraform instances with AWS.
Join the DZone community and get the full member experience.
Join For FreeIn my previous article, I did give an overview of Terraform. This article will help us to understand how to spin up instances in AWS using the Infrastructure as a Code tool Terraform. Although it's beyond the scope to discuss all the commands, I will try to cover the basic commands, and other resources can be researched and tried from the Terraform website against the provider of your choice.
You might also enjoy Linode's Beginner's Guide to Terraform.
Amazon Web Services (AWS) is a secure cloud services platform provided by Amazon. There are millions of customers who use AWS for their daily computing needs. AWS offers:
Compute capacity,
Storage,
DB,
And much more.
Big organizations who use AWS or any other cloud service provider do need to use some IaaC tool to spin up EC2 instances for their applications. It would be tedious to spin up EC2 instances manually.
Terraform's purpose is to deploy the server itself, CHEF would configure items in your server once you have the infrastructure. Let's learn in brief how to manage infrastructure as code using Terraform.
You have to download Terraform or use Brew command to install Terraform if using MAC. Also, you need to have an AWS account and need to add the AWS credentials (AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
) as environment variables to start using the TF with AWS.
Terraform State
Terraform supports many cloud providers and has resources for each cloud provider:
Resources are defined as a code in Terraform:
provider "aws" {
region = "ap-south-1"
}
resource "aws_instance"
"example" {
ami = "ami-4fc58420"
instance_type = "t2.micro"
tags {
Name = "terraform-example"
}
}
The above configuration creates a single EC2 instance in AWS.
Use terraform init
, a command to initialize download provider plugins to your local system. The output of the above command is shown below:
Initializing provider plugins...
- Checking for available provider plugins
- Downloading plugin for provider "aws" (0.1.4)...
* provider.aws: version = "~> 0.1"
Terraform has been successfully initialized!
After initializing, type the terraform plan
command to see what are you going to deploy. The output of plan command is as below:
+ aws_instance.example
id: <computed>
ami: "ami-4fc58420"
associate_public_ip_address: <computed>
availability_zone: <computed>
ebs_block_device.#: <computed>
ephemeral_block_device.#: <computed>
instance_state: <computed>
instance_type: "t2.micro"
ipv6_address_count: <computed>
ipv6_addresses.#: <computed>
key_name: <computed>
source_dest_check: "true"
Plan: 1 to add, 0 to change, 0 to destroy.
The plan command tells you what TF is about to do; a few will be filled in and some will be computed. Use the terraform apply
command to apply the changes.
$ terraform apply
aws_instance.example: Creating...
ami: "" => "ami-4fc58420"
associate_public_ip_address: "" => "<computed>"
availability_zone: "" => "<computed>"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_state: "" => "<computed>"
aws_instance.example: Still creating... (10s elapsed)
aws_instance.example: Still creating... (20s elapsed)
aws_instance.example: Creation complete after 22s (ID: i-07fcaa5435207dac7)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
The EC2 instance is up and running with the name "terraform-example."
Your configuration can be parameterized using variables:
variable "name" {
description = "My EC2 instance"
}
Define a variable and its description. The default value is optional:
provider "aws" {
region = "ap-south-1"
}
variable "name" {
description = "My EC2 instance"
value = "foo"
}
resource "aws_instance"
"example" {
ami = "ami-4fc58420"
instance_type = "t2.micro"
tags {
Name = "${var.name}"
}
}
Running the plan command will show different information now.
~ aws_instance.example
tags.Name: "terraform-example" => "foo"
Plan: 0 to add, 1 to change, 0 to destroy.
Notice the signs when you ran terraform plan
the first time and now.
+ says that a new configuration will be added.
~ says that the configuration needs a change.
- says that the configuration will be deleted.
You can clean all your resources using TF.
terraform destroy
aws_instance.example: Refreshing state... (ID: i-07fcaa5435207dac7)
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
- aws_instance.example
Plan: 0 to add, 0 to change, 1 to destroy.
The State of Terraform
You must be wondering, how does TF know what needs to be changed or destroyed when we issue the plan/apply command? Usually, Terraform records the state of everything it has done, so it stores the state locally as .tfstate files.
$ ls -al
-rw-r--r-- 1 suniljacob staff 317 Nov 13 20:53 terraform.tfstate
-rw-r--r-- 1 suniljacob staff 3276 Nov 13 20:53 terraform.tfstate.backup
Usually, it's not advised to store the state in local hard, as it may contain sensitive data, so it would be good to use a backend like S3 or Consul to store Terraform state information.
Modules
These are blueprints for TF configuration. A module is just a folder within Terraform files.
module "myfrontend" { //give module identifier
source = "../terraform-example" //path where the module lies
instance_name = "frontend"
}
They are like functions and can be called many times, instead of writing the same configuration code for different requirements.
Loops
Since Terraform is declarative, very little logic needs to be written in it. There is a count parameter which helps us to create loops in TF. The below code creates one EC2 instance:
provider "aws" {
region = "ap-south-1"
}
resource "aws_instance"
"example" {
count = 1
ami = "ami-4fc58420"
instance_type = "t2.micro"
}
The below code creates three EC2 instances:
provider "aws" {
region = "ap-south-1"
}
resource "aws_instance"
"example" {
count = 3
ami = "ami-4fc58420"
instance_type = "t2.micro"
tags {
Name = "${var.instance_name}-${count.index+1}" //Interpolation Syntax
}
}
Use count.index to modify each iteration. The above code creates three EC2 instances, each with a different name. Using count is like using for loop in other languages.
Layout of Files
We use three main files while using TF:
main.tf -> This is used to declare resources needed for your configuration.
vars.tf -> This will hold variables to be used in main.tf.
outputs.tf -> This file will hold any output variables.
Best Practices
It's good to use GitHub when working as a team with TF. Use pull requests, merge the code, and deploy.
Use the DEV environment and test your TF configuration code before moving to production. Always run a plan and be extremely careful with deletes. There is no rollback once the configuration is applied.
Manage your secrets as environment variables and deploy to your shared environments from one master branch.
If you plan to use Terraform for setting up your infrastructure, this article will surely serve as a starting point.
Opinions expressed by DZone contributors are their own.
Comments