The enabling idea of Infrastructure as Code is that the systems and devices used to run software can be treated as if they, themselves, are software.

-Infrastructure as Code by Kief Morris

I had created two videos on YouTube:

In this article, we’re going to install Terraform on Mac OSX and deploy an EC2 instance on AWS using Terraform rather than manual deployment by clicking AWS EC2 Web Console.

Create a directory under $HOME, Download and Unzip Terraform.

$ mkdir terraform

$ cd $HOME/terraform



$ curl -O https://releases.hashicorp.com/terraform/0.11.7/terraform_0.11.7_darwin_amd64.zip



% Total % Received % Xferd Average Speed Time Time Time Current



Dload Upload Total Spent Left Speed



100 16.9M 100 16.9M 0 0 18.7M 0 --:--:-- --:--:-- --:--:-- 18.7M



$ unzip terraform_0.11.7_darwin_amd64.zip



Archive: terraform_0.11.7_darwin_amd64.zip



inflating: terraform

Setting PATH under ~/.bash_profile

# Setting PATH for Terraform



TERRAFORM=~/terraform/



PATH=$PATH:$TERRAFORM

Open a New Terminal and Verify.

$ terraform --version



Terraform v0.11.7 $ terraform



Usage: terraform [--version] [--help] <command> [args]

The available commands for execution are listed below.

The most common, useful commands are shown first, followed by

less common or more advanced commands. If you're just getting

started with Terraform, stick with the common commands. For the

other commands, please read the help and docs before usage.

Common commands:



apply Builds or changes infrastructure



console Interactive console for Terraform interpolations



destroy Destroy Terraform-managed infrastructure



env Workspace management



fmt Rewrites config files to canonical format



get Download and install modules for the configuration



graph Create a visual graph of Terraform resources



import Import existing infrastructure into Terraform



init Initialize a Terraform working directory



output Read an output from a state file



plan Generate and show an execution plan



providers Prints a tree of the providers used in the configuration



push Upload this Terraform module to Atlas to run



refresh Update local state file against real resources



show Inspect Terraform state or plan



taint Manually mark a resource for recreation



untaint Manually unmark a resource as tainted



validate Validates the Terraform files



version Prints the Terraform version



workspace Workspace management







All other commands:



debug Debug output management (experimental)



force-unlock Manually unlock the terraform state



state Advanced state management

Congratulations !!! Terraform is up and running.

Let’s spin up a virtual machine in AWS by using Terraform. We have to have AWS Account already, else ywe can create one here.

We gonna create a profile called “terraform” under ~HOME/.aws where our AWS config and credentials are stored.

$ cd .aws

$ more credentials



[terraform]

aws_access_key_id= [paste-access-key-here]

aws_secret_access_key= [paste-secret-access-key-here]



$ more config

[profile terraform]

region = us-east-1

output = json

Create a terraform configuration called “webserver.tf” under $HOME/terraform.

$ more webserver.tf

provider "aws" {

region = "us-east-1"

shared_credentials_file = "/Users/hellocloud/.aws/credentials"

profile = "terraform"

}



resource "aws_instance" "web_svr" {

ami = "ami-1c47407f"

instance_type = "t2.micro"

key_name = "helloterraform"

}

Run the command $ terraform plan, and observe the output.

$ terraform plan

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_instance.web_svr

ami: "ami-1c47407f"

associate_public_ip_address: "<computed>"

availability_zone: "<computed>"

ebs_block_device.#: "<computed>"

ephemeral_block_device.#: "<computed>"

instance_state: "<computed>"

instance_type: "t2.micro"

ipv6_addresses.#: "<computed>"

key_name: "helloterraform"

network_interface_id: "<computed>"

placement_group: "<computed>"

private_dns: "<computed>"

private_ip: "<computed>"

public_dns: "<computed>"

public_ip: "<computed>"

root_block_device.#: "<computed>"

security_groups.#: "<computed>"

source_dest_check: "true"

subnet_id: "<computed>"

tenancy: "<computed>"

vpc_security_group_ids.#: "<computed>"





Plan: 1 to add, 0 to change, 0 to destroy.

Run the command $ terraform apply, and observe the output.

$ terraform apply

aws_instance.web_svr: Creating...

ami: "" => "ami-1c47407f"

associate_public_ip_address: "" => "<computed>"

availability_zone: "" => "<computed>"

ebs_block_device.#: "" => "<computed>"

ephemeral_block_device.#: "" => "<computed>"

instance_state: "" => "<computed>"

instance_type: "" => "t2.micro"

ipv6_addresses.#: "" => "<computed>"

key_name: "" => "helloterraform"

network_interface_id: "" => "<computed>"

placement_group: "" => "<computed>"

private_dns: "" => "<computed>"

private_ip: "" => "<computed>"

public_dns: "" => "<computed>"

public_ip: "" => "<computed>"

root_block_device.#: "" => "<computed>"

security_groups.#: "" => "<computed>"

source_dest_check: "" => "true"

subnet_id: "" => "<computed>"

tenancy: "" => "<computed>"

vpc_security_group_ids.#: "" => "<computed>"

aws_instance.web_svr: Still creating... (10s elapsed)

aws_instance.web_svr: Creation complete



Apply complete! Resources: 1 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: terraform.tfstate

There will be a file called “terraform.tfstate” is created. That state file is extremely important because it maps various resource metadata to actual resource IDs so that Terraform knows what it is managing. That file must be saved and distributed to anyone who might run Terraform. [ excerpted from : https://www.terraform.io/ ]

Run the command $ terraform show to verify.

$ terraform show

aws_instance.web_svr:

id = i-03caa2b3676820d9d

ami = ami-1c47407f

associate_public_ip_address = true

availability_zone = ap-southeast-2b

disable_api_termination = false

ebs_block_device.# = 0

ebs_optimized = false

ephemeral_block_device.# = 0

iam_instance_profile =

instance_state = running

instance_type = t2.micro

ipv6_address_count = 0

ipv6_addresses.# = 0

key_name = helloterraform

monitoring = false

network_interface_id = eni-f80d9c83

private_dns = ip-172-31-14-81.ap-southeast-2.compute.internal

private_ip = 172.31.14.81

public_dns = ec2-13-55-176-59.ap-southeast-2.compute.amazonaws.com

public_ip = 13.55.176.59

root_block_device.# = 1

root_block_device.0.delete_on_termination = true

root_block_device.0.iops = 100

root_block_device.0.volume_size = 8

root_block_device.0.volume_type = gp2

security_groups.# = 0

source_dest_check = true

subnet_id = subnet-ea4f928e

tags.% = 0

tenancy = default

vpc_security_group_ids.# = 1

vpc_security_group_ids.2657148695 = sg-1e683a7a

Let’s login to AWS Console and verify.

Cool !!!

But, we forgot to tag the instance. So let’s edit webserver.tf as below.

provider "aws" {

region = "ap-southeast-2"

shared_credentials_file = "/Users/hellocloud/.aws/credentials"

profile = "terraform"

}



resource "aws_instance" "web_svr" {

ami = "ami-1c47407f"

instance_type = "t2.micro"

key_name = "helloterraform"

tags = { Name = "web_svr"}

}

Now we gonna repeat the same terraform process we’ve done.

$ terraform plan

$ terraform apply

$ terraform show

Login to AWS Console and verify the Name Column.

Let’s clean up by typing $ terraform plan -destroy.

$ terraform plan -destroy

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.



aws_instance.web_svr: Refreshing state... (ID: i-03caa2b3676820d9d)



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_instance.web_svr





Plan: 0 to add, 0 to change, 1 to destroy.

Let’s destroy now. $ terraform destroy.

$ terraform destroy

Do you really want to destroy?

Terraform will delete all your managed infrastructure.

There is no undo. Only 'yes' will be accepted to confirm.



Enter a value: yes



aws_instance.web_svr: Refreshing state... (ID: i-03caa2b3676820d9d)

aws_instance.web_svr: Destroying...

aws_instance.web_svr: Still destroying... (10s elapsed)

aws_instance.web_svr: Still destroying... (20s elapsed)

aws_instance.web_svr: Still destroying... (30s elapsed)

aws_instance.web_svr: Still destroying... (40s elapsed)

aws_instance.web_svr: Still destroying... (50s elapsed)

aws_instance.web_svr: Still destroying... (1m0s elapsed)

aws_instance.web_svr: Destruction complete



Destroy complete! Resources: 1 destroyed.

Verify on AWS Console.

Terminated !!!

Now we got the idea of Infrastructure as Code using Terraform.

What about we wanna automate or define resources, such as VMs, Networks, Storage and Containers, as IaC of Google Cloud, Azure, Docker, Kubernetes, etc. Check it out Terraform Providers.