Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

How to Efficiently Manage Your Application Infrastructure with Terraform

Infrastructure as Code (IaC) is one of the DevOps directions that allows managing application infrastructure in the format of code. Moreover, it helps simplify scaling and control of the infrastructure as well as shorten the cycle of application deployment and delivery.
One of the most powerful tools for working with application infrastructure is Terraform. In this article, we’ll consider a practical use of Terraform, elaborating on its advantages and disadvantages. Let’s go!

What actually is Terraform?

Developed by HashiCorp, Terraform is an open source tool that allows you to safely and predictably create, change, and improve the infrastructure of your application. Terraform codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.

Creating a Terraform configuration is similar to the description of infrastructural components of your application. The description format is pretty declarative. In a nutshell, it relies on a dedicated programming language called “HashiCorp Configuration Language” (HCL). However, you can also use good ol’ JSON.

How does it look in practice?

In the first example, we’re going to create AWS VPC with a subnetwork. To have a better understanding of the configuration details, we’ll be referring to AWS documentation.

First, we need to create a direction called “infrastructure” and describe all the configurations necessary for deployment. Since Terraform retrieves all the files with the .tf extension from the directory, we can split the code into separate config-modules. This will allow simplifying the process of searching and changing specific parts of the infrastructure.

The next step is to describe the provider. In our case, it’s AWS.

aws_provider.tf

variable “access_key_id” {
type = “string”
}
variable “secret_access_key” {
type = “string”
}
variable “region” {
type = “string”
}
provider “aws” {
access_key = “${var.access_key_id}”
secret_key = “${var.secret_access_key}”
region = “${var.region}”
}

Here ‘${}’ is used for interpolation. This allows you to find out which values are entered manually.

After that, we need to describe the VPC resource using the following construction:

vpc.tf

resource "aws_vpc" "vpc-jetruby" {
cidr_block = "10.0.0.0/16"

tags {
Name = "VPC"
}
}

The only parameter necessary to create VPC is CIDR block.

Now we need to provide all the resources that are located in VPC with access to the Internet. To do that, we need to create an Internet gateway and connect it to VPC.

gateway.tf

resource "aws_internet_gateway" "gateway-jetruby" {
vpc_id = "${aws_vpc.vpc-jetruby.id}"
tags {
Name = "Intenet Gateway"
}
}

Next, we need to describe the subnetwork and connect it with VPC. Let’s assume that VPC will have only one network covering the the entire list of addresses.

subnet.tf

resource "aws_subnet" "subnet-jetruby" {
vpc_id = "${aws_vpc.vpc-jetruby.id}"
cidr_block = "10.0.0.0/16"
map_public_ip_on_launch = "true"
tags {
Name = "Subnet"
}
}
output "aws-id-subnet-jetruby" {
value = "${aws_subnet.subnet-jetruby.id}"
}

Take note of the command/variable “output” (we didn’t describe it). It allows you to specify which data Terraform has to remember and return to a user after the execution.

Now when we have the subnetwork, we need to describe a few final steps. AWS automatically associates the subnetwork with Main Route Table that is created for every VPC. Nevertheless, if we want to have full control over the outgoing traffic, we need to create a RouteTable for the subnetwork.

route-table.tf

resource "aws_route_table" "route-table-jetruby" {
vpc_id = "${aws_vpc.vpc-jetruby.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.gateway-jetruby.id}"
}
tags {
Name = "Route Table"
}
}

It’s time to make it work. The only thing we need to do is describe the association with RouteTable.

route-table-association.tf

resource "aws_route_table_association" "route-table-association-jetruby" {
subnet_id = "${aws_subnet.subnet-jetruby.id}"
route_table_id = "${aws_route_table.route-table-jetruby.id}"
}

So far, we’ve described the entire VPC infrastructure and subnetworks. Now let’s have a look at all the files created in the directory and run planning. Planning is an operation that will allow you to understand what will be happening in the process “apply”. Basically, it’s a simulation of a real infrastructure deployment.

shell.sh

➔ ls -lah
total 48
drwxr-xr-x 8 alxgol staff 272B 23 окт 00:25 .
drwxr-xr-x 263 alxgol staff 8,7K 23 окт 00:09 ..
-rw-r--r-- 1 alxgol staff 271B 18 окт 15:51 aws_provider.tf
-rw-r--r-- 1 alxgol staff 125B 23 окт 00:24 gateway.tf
-rw-r--r-- 1 alxgol staff 193B 23 окт 00:24 route-table-association.tf
-rw-r--r-- 1 alxgol staff 229B 23 окт 00:24 route-table.tf
-rw-r--r-- 1 alxgol staff 262B 23 окт 00:24 subnet.tf
-rw-r--r-- 1 alxgol staff 97B 23 окт 00:25 vpc.tf
➔ terraform plan
var.access_key_id
Enter a value: access-key
var.region
Enter a value: eu-west-2
var.secret_access_key
Enter a value: secret-key
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage.
The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read.
Note: You didn't specify an "-out" parameter to save this plan, so when "apply" is called, Terraform can't guarantee this is what will execute.
+ aws_internet_gateway.gateway-jetruby
tags.%: "1"
tags.Name: "Intenet Gateway"
vpc_id: "${aws_vpc.vpc-jetruby.id}"
+ aws_route_table.route-table-jetruby
route.#: "1"
route.~222644434.cidr_block: "0.0.0.0/0"
route.~222644434.egress_only_gateway_id: ""
route.~222644434.gateway_id: "${aws_internet_gateway.gateway-jetruby.id}"
route.~222644434.instance_id: ""
route.~222644434.ipv6_cidr_block: ""
route.~222644434.nat_gateway_id: ""
route.~222644434.network_interface_id: ""
route.~222644434.vpc_peering_connection_id: ""
tags.%: "1"
tags.Name: "Route Table"
vpc_id: "${aws_vpc.vpc-jetruby.id}"
+ aws_route_table_association.route-table-association-jetruby
route_table_id: "${aws_route_table.route-table-jetruby.id}"
subnet_id: "${aws_subnet.subnet-jetruby.id}"
+ aws_subnet.subnet-jetruby
assign_ipv6_address_on_creation: "false"
availability_zone: ""
cidr_block: "10.0.0.0/16"
ipv6_cidr_block: ""
ipv6_cidr_block_association_id: ""
map_public_ip_on_launch: "true"
tags.%: "1"
tags.Name: "Subnet"
vpc_id: "${aws_vpc.vpc-jetruby.id}"
+ aws_vpc.vpc-jetruby
assign_generated_ipv6_cidr_block: "false"
cidr_block: "10.0.0.0/16"
default_network_acl_id: ""
default_route_table_id: ""
default_security_group_id: ""
dhcp_options_id: ""
enable_classiclink: ""
enable_dns_hostnames: ""
enable_dns_support: "true"
instance_tenancy: ""
ipv6_association_id: ""
ipv6_cidr_block: ""
main_route_table_id: ""
tags.%: "1"
tags.Name: "VPC"
Plan: 5 to add, 0 to change, 0 to destroy.

Terraform created a plan based on the described configuration. According to this plan, it’ll create 5 resources in the Eu-West-2 (London) region in the AWS account:

  1. VPC
  2. Gateway
  3. Subnet
  4. Route Table
  5. Route Table Association

So far so good. Let’s try to execute the operation “apply” used for real infrastructure deployment on AWS.

➔ terraform apply
var.access_key_id
Enter a value: access-key
var.region
Enter a value: eu-west-2
var.secret_access_key 
Enter a value: secret-key
aws_vpc.vpc-jetruby: Creating...
assign_generated_ipv6_cidr_block: "" => "false"
cidr_block: "" => "10.0.0.0/16"
default_network_acl_id: "" => ""
default_route_table_id: "" => ""
default_security_group_id: "" => ""
dhcp_options_id: "" => ""
enable_classiclink: "" => ""
enable_dns_hostnames: "" => ""
enable_dns_support: "" => "true"
instance_tenancy: "" => ""
ipv6_association_id: "" => ""
ipv6_cidr_block: "" => ""
main_route_table_id: "" => ""
tags.%: "" => "1"
tags.Name: "" => "VPC"
aws_vpc.vpc-jetruby: Creation complete (ID: vpc-02d7836b)
aws_internet_gateway.gateway-jetruby: Creating...
tags.%: "0" => "1"
tags.Name: "" => "Intenet Gateway"
vpc_id: "" => "vpc-02d7836b"
aws_subnet.subnet-jetruby: Creating...
assign_ipv6_address_on_creation: "" => "false"
availability_zone: "" => ""
cidr_block: "" => "10.0.0.0/16"
ipv6_cidr_block: "" => ""
ipv6_cidr_block_association_id: "" => ""
map_public_ip_on_launch: "" => "true"
tags.%: "" => "1"
tags.Name: "" => "Subnet"
vpc_id: "" => "vpc-02d7836b"
aws_internet_gateway.gateway-jetruby: Creation complete (ID: igw-ebdd4e82)
aws_route_table.route-table-jetruby: Creating...
route.#: "" => "1"
route.698417740.cidr_block: "" => "0.0.0.0/0"
route.698417740.egress_only_gateway_id: "" => ""
route.698417740.gateway_id: "" => "igw-ebdd4e82"
route.698417740.instance_id: "" => ""
route.698417740.ipv6_cidr_block: "" => ""
route.698417740.nat_gateway_id: "" => ""
route.698417740.network_interface_id: "" => ""
route.698417740.vpc_peering_connection_id: "" => ""
tags.%: "" => "1"
tags.Name: "" => "Route Table"
vpc_id: "" => "vpc-02d7836b"
aws_subnet.subnet-jetruby: Creation complete (ID: subnet-62e4a219)
aws_route_table.route-table-jetruby: Creation complete (ID: rtb-34f8d45d)
aws_route_table_association.route-table-association-jetruby: Creating...
route_table_id: "" => "rtb-34f8d45d"
subnet_id: "" => "subnet-62e4a219"
aws_route_table_association.route-table-association-jetruby: Creation complete (ID: rtbassoc-103a2079)
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.
State path:
Outputs:
aws-id-subnet-jetruby = subnet-62e4a219

Great! You must have noticed that, at the final stage of operation, Terraform moved the subnetworks to “output ID.” Now we need to make sure that everything described there is actually created.

We’ll go to AWS and check whether we have a new Virtual Private Cloud with the “VPC” name.

After that, we need to check the Internet Gateway with the created VPC.

Everything seems to check out. Now let’s have a look at the subnetworks. Our job is to find the Subnet ID that we got in “output” after “apply” (‘subnet-62e4a219’).

Great! Now we need to make sure that subnetwork’s association with the Route Table has been successful. Let’s find Route Table using its ID described in the created Subnet.

Voila! That’s basically it, folks!

The Bottom Line

As you can see, Terraform is quite simple to work with and comprehend even if you’ve never had experience with the HCL syntax. Speaking of more specific aspects, we can outline the following:

Andvantages:

  • Comprehensive documentation.
  • Declarative and easy-to-understand configuration syntax.
  • The ability to work with both popular providers like AWS and custom solutions.
  • State management. Terraform automatically determines which part of your configuration is already deployed, which one should be removed, and which one should be added.
  • Helpful and active community.
  • Immutability (however, it’s both an advantage and a disadvantage at the same time).

Disadvantages:

  • Immutability. When several people are working on the same configuration, someone can easily rewrite the statefile used by Terraform during the “plan” and “apply” operations, which can lead to unforeseen consequences.
  • Terraform stores the statefile in a text format. This can be a issue when using version control systems. If someone corrupts it when merging or any other operation, you’d have to deploy the entire infrastructure once again.

Summing up, Terraform is a great tool for application infrastructure management. If you’re careful enough, the aforementioned disadvantages won’t be an issue, making the tool an even better solution. As for our own experience, using Terraform enabled us to streamline our development processes and, consequently, deliver projects to our clients faster.

P/S: If you liked the article, please support it with claps and by hitting the subscribe button below! Cheers!

How to Efficiently Manage Your Application Infrastructure with Terraform was originally published in JetRuby on Medium, where people are continuing the conversation by highlighting and responding to this story.



This post first appeared on JetRuby Agency - Featured Technical Stories Based In Our Experience, please read the originial post: here

Share the post

How to Efficiently Manage Your Application Infrastructure with Terraform

×

Subscribe to Jetruby Agency - Featured Technical Stories Based In Our Experience

Get updates delivered right to your inbox!

Thank you for your subscription

×