Thursday, January 20, 2022

Terraform 101

 Terraform 101

Terraform is used for Infrastructure as Code (IaC).

Terraform is Declarative, NOT Imperative, and defines the DESIRED STATE.

What does that mean? For initial infrastructure creation, they will be very similar (e.g. both will say create 5 servers), but when you update your infrastructure there are differences.

For example, say you have 10 servers, and you want to remove 3...

Imperative commands to update your infrastructure would look like:

- remove 3 servers

Declarative commands to update your infrastructure would look like:

- have 7 servers


Terraform will work out what it needs to do to achieve the Desired state.

With Terraform, you re-run the whole configuration file to achieve your update.

Terraform Stages

refresh - query infra to get current state

plan - create an execution plan (plan to achieve the desired state, based on the current state). No changes.

apply - execute the plan

destroy - removes whole setup, removing elements in the correct order. E.g. remove servers before remove VPC. Destroy also runs a Refresh, and then a Plan before removing the resources.

Terraform plugin for VSCode

https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform


Install Terraform on Mac

First install Homebrew - https://brew.sh/

https://learn.hashicorp.com/tutorials/terraform/install-cli

brew tap hashicorp/tap

brew install hashicorp/tap/terraform

brew update

brew upgrade hashicorp/tap/terraform


Terraform Basic Operation

In vscode, create a new directory - e.g. Documents\terraform

create the file: main.tf

provider "aws" {
region = "us-east-1"
access_key = "access-key"
secret_key = "your-secret-key"
}

resource "aws_vpc" "myvpc" {
cidr_block = "10.0.0.0/16"
}


This will create a VPC resource - for syntax see:

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc


In VSCode, click the 'View' menu and select "Terminal".

Now, run the command:

terraform init



Initializing the backend... Initializing provider plugins... - Reusing previous version of hashicorp/aws from the dependency lock file - Using previously-installed hashicorp/aws v3.72.0 Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.

Terraform has successfully initialised the plugin for AWS.

terraform plan



The terraform plan command examines the current state, and works out what needs to be changed in order to achieve the desired state.

In the main.tf file we specified a VPC with CIDR 10.0.0.0/16, and here terraform can see that it currently doesn't exist - hence the (known after apply) lines.
For example the arn (amazon resource name) for the VPC is unknown because we haven't created it yet.


Terraform Apply


Again, the apply command examines the current state, and says what it will do in order to achieve the desired state.
Type 'yes' to continue to perform the actions.




Terraform Destroy


This will destroy the resources listed in your main.tf file.


Terraform will examine the current state, and will say what actions it will take to destroy the resources.
Type 'yes' to continue.




State File

The state file is called 'terraform.tfstate'. This contains the current state.
There is also a back file called 'terraform.tfstate.backup', but this isn't the latest.

When you run an plan, apply, or destroy command, the terraform.tfstate file will be updated. The old contents of the file will be copied to the backup file.

Variables

Defined in the main.tf file.

Variables are a way of setting a value which can be used multiple times.
Variables can be a string, number, boolean, list, map, tuple, or object.

String Variables











Number Variables










Boolean Variables








List Variables

Lists can contain strings, numbers, or boolean values.







Note for lists, like an array, the first element is accessed by item number 0.
The value of item 0 = 'Value1'

Map Variables

Maps are key-value pairs.

The elements of a map are accessed using the key you gave,
For example:














When you access key1, its value is 'Value1'.

Tuples

Tuples are similar to Lists, but can contain different data types.

variable "mytuple" {
type = tuple([string, number, string])
default = ["cat",1,"dog"]
}


Objects

variable "myobject"{
type = object({name = string, port = list(number)})
default = {
name = "fw"
port = [22,25,80]
}
}


Using Variables

Variables are referenced using 'var.'
variable "vpcname" {
type = string
default = "myvpc"
}

resource "aws_vpc" "myvpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = var.vpcname
}
}


Or to access a list variable:
variable "mylist" {
type = list(string)
default = [ "Value1","Value2" ]
}

resource "aws_vpc" "myvpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = var.mylist[0]
}
}


Or to access a map variable:
variable "mymap" {
type = map
default = {
key1 = "Value1"
key2 = "Value2"
}
}

resource "aws_vpc" "myvpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = var.mymap["key1"]
}
}

Note, the key name is in quotes!


Input Variables

Allows user to manually specify a value when running terraform plan
variable "inputname" {
type = string
description = "set the name of the vpc"
}

resource "aws_vpc" "myvpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = var.inputname
}
}

Now when running terraform plan, you will see:







Outputs

After Terraform creates a resource, you may want to know some information about it such as the arn or id. Note, this will only work with terraform apply.

To see which attributes can be fetched, see the Terraform documentation, e.g gor AWS VPC resource, the attributes are:  https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc

resource "aws_vpc" "myvpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = var.inputname
}
}
output "vpcid" {
value = aws_vpc.myvpc.id
}
output "vpcarn" {
value = aws_vpc.myvpc.arn
}







Note: the outputs get saved to the State file terraform.tfstate


Creating an EC2 instance

The documentation for EC2 instance is 'aws_instance'


main.tf
provider "aws" {
region = "us-east-1"
}

resource "aws_instance" "ec2instance" {
ami = "ami-08e4e35cccc6189f4"
instance_type = "t2.micro"
}

output "ec2_arn" {
value = aws_instance.ec2instance.arn
}














No comments: