Skip to content

Instantly share code, notes, and snippets.

@roz0n
Created February 1, 2021 20:40
Show Gist options
  • Save roz0n/575d6b2f4cf6c7aabbfd49a05f677d67 to your computer and use it in GitHub Desktop.
Save roz0n/575d6b2f4cf6c7aabbfd49a05f677d67 to your computer and use it in GitHub Desktop.
IAC with Terraform

IAC with Terraform

What and Why

  • 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
  • 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

Advantages

  • 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

Deploying an EC2 Instance

  1. Download the Terraform binary and store it somewhere, we'll need it in a bit

  2. 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
  3. Create a dir to store everything corresponding to this project/deployment. Within it, create a test.tf file that will contain our Terraform script.

  4. Inside that file, add the following:

    provider "aws" {
        access_key = "[your access key]"
        secret_key = "[your private key]"
        region = "us-east-2"
    }
  5. 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"
       }
  6. Run terraform init to kick things off. It should download dependencies and store them inside .terraform

  7. 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.
  8. And now finally, use terraform apply to apply the configuration we've outlined in our .tf file and apply those changes on AWS.

  9. 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.

Implementing Variables

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.

Assigning variables

There's a few ways to assign variables...

CLI flags with -var:

terraform apply -var instance_type="t2.micro"

From a file in the root directory named terraform.tfvars:

terraform apply -var instance_type="t2.micro"

From environment variables prefixed with TF_VAR_*:

TF_VAR_instance_type=t2.micro

Within the test.tf file itself
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.

output variables

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

Destroy and redeploy

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment