- 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
HCLand good ol'JSON- We'll start with
HCLlater 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.tffile 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
microderivative 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
.tfin its own block like so:
resource "aws_instance" "ec2_instance" { ami = "ami-0cf31d971a3ca20d6" instance_type = "t2.micro" }
-
-
Run
terraform initto kick things off. It should download dependencies and store them inside.terraform -
Once that's done, run
terraform planto 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 applyto apply the configuration we've outlined in our.tffile and apply those changes on AWS. -
If we typed everything correctly, this should've pinned up a new EC2 instance and generated a
terraform.tfstatefile. 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.