- Terraform is a tool used for building, changing, and versioning infrastructure safely and efficiently
- It supports many service providers, likewise one could roll their own custom or in-house solutions
- IAC is defined using high-level languages
HCL
and good ol'JSON
- We'll start with
HCL
later on as it's more commonly used for these purposes
- We'll start with
- Sysadmins used to purchase hardware, set up servers with network and software, and also maintain/modify them manually
- Repetitive and time consuming
- By definition, IAC is the process of managing and provisioning infrastructure through code instead of physical hardware configuration and interactive configuration tools
- Reusable: Same code can be used for multiple environments
- Maintainable: Code can be pushed to version control
- Extensible: Code can be added to extend infrastructure
- Testable: Code can be tested against expected behavior for reliability
- Repeatable: We write code once and run it multiple times and get the same results
- Documentation: Code can be documented for better understanding.
- Shareable: Code can be shared among developers to perform the same task across the org.
- Auditable: All changes are done as code and one can track changes.
As a result, we now have a predictable process for developing, maintaining and deploying IAC:
Code -> Version Control -> Code Review -> Validate -> Create Infrastructure
-
Download the Terraform binary and store it somewhere, we'll need it in a bit
-
Create an AWS account if you do not have one already
- Head over to IAM, follow these instructions to generate a new access key and private key pair
-
Create a dir to store everything corresponding to this project/deployment. Within it, create a
test.tf
file that will contain our Terraform script. -
Inside that file, add the following:
provider "aws" { access_key = "[your access key]" secret_key = "[your private key]" region = "us-east-2" }
-
Next, we'll declare an EC2 instance of instance type T2 Micro with AMI:
ami-0742a572c2ce45ebf
-
Learn more about EC2 instance types. In short, a T2 instances provide baseline CPU performance with the ability to exceed that if needed. The
micro
derivative of T2 instances are cheap and have low to moderate network performance as the name implies. -
An AMI is an Amazon Machine Image. As the name suggests, it's an image that we'll use to spin up a VM.
- The AMI above corresponds to an Ubuntu Server 20.04 LTS (HVM), SSD Volume Type
- I chose this one because I've used Debian-based distros in the past, but there are many other kinds of AMIs that are free-tier eligible. You can view all available options and their AMIs by heading over to EC2, and clicking launch instance.
- So add that to the
.tf
in its own block like so:
resource "aws_instance" "ec2_instance" { ami = "ami-0cf31d971a3ca20d6" instance_type = "t2.micro" }
-
-
Run
terraform init
to kick things off. It should download dependencies and store them inside.terraform
-
Once that's done, run
terraform plan
to create an execution plan.- Essentially, this is a way to check whether our set of instructions match our expectations before we deploy without making any changes to the infrastructure itself.
-
And now finally, use
terraform apply
to apply the configuration we've outlined in our.tf
file and apply those changes on AWS. -
If we typed everything correctly, this should've pinned up a new EC2 instance and generated a
terraform.tfstate
file. That file used to map real-world resources to the configuration we specified and keep track of metadata.
Now let's run through implementing variables, and specifying the output
variable.
In the real-world, we'll likely want to change things like the AMI or the instance type based on some variable. According to the docs, variables should not be part of our resource code and should instead be injected from CLI arguments and env variables.
There's a few ways to assign variables...
terraform apply -var instance_type="t2.micro"
terraform apply -var instance_type="t2.micro"
TF_VAR_instance_type=t2.micro
variable "instance_type" {
default = "t2.micro"
}
variable "ami" {
default = "ami-0cf31d971a3ca20d6"
}
resource "aws_instance" "ec2_instance" {
ami = var.ami
instance_type = var.instance_type
}
For now, the latter works best for the sake of simplicity.
Upon creating an instance, Terraform can be instructed to output data related to its configuration.
Add this to the test.tf
file:
output "ip" {
value = "${aws_instance.ec2_instance.public_ip}"
}
At this point, the test.tf
file looks like so:
variable "instance_type" {
default = "t2.micro"
}
variable "ami" {
default = "ami-0cf31d971a3ca20d6"
}
provider "aws" {
access_key = "[access_key]"
secret_key = "[secret_key]"
region = "us-east-2"
}
resource "aws_instance" "ec2_instance" {
ami = var.ami
instance_type = var.instance_type
}
output "ip" {
value = "${aws_instance.ec2_instance.public_ip}"
}
Likewise, the current directory looks like so:
├── terraform
├── terraform.tfstate
├── terraform.tfstate.backup
└── test.tf
To destroy the previously deployed instance, run terraform destroy
.
Once that's complete, run terraform plan
and terraform apply
again to deploy a new instance with the updated Terraform script.
Terraform should now output the ip
of the instance we just created.