DEV Community

Cover image for Mastering Basic Infrastructure with Terraform
marvintowett
marvintowett

Posted on

Mastering Basic Infrastructure with Terraform

Yesterday we deployed our first server. Today we level up. We will learn one of the most important principles in Terraform β€” and in software engineering generally β€” which isΒ DRY: Don't Repeat Yourself. We will apply it by deploying a configurable web server using input variables, then take it further by deploying a clustered web server capable of handling real traffic. By the end of today we will understand what separates a toy deployment from production-ready infrastructure.

We will continue using our code from yesterday's session and improve on it. Here is our starting point:

provider "aws" {
  region = "us-west-2"
}

resource "aws_instance" "example" {
    ami          = "ami-0735c191cf914754d"
    instance_type = "t3.micro"
    vpc_security_group_ids = [aws_security_group.instance.id]

    tags = {
      Name = "mk-terraform-example"
    }

    user_data = <<-EOF
                    #!/bin/bash
                    echo "Hello, World" > index.html
                    nohup busybox httpd -f -p 8080 &
                EOF

    user_data_replace_on_change = true

}

resource "aws_security_group" "instance" {
    name  = "mk-terraform-security-group"

    ingress {
        from_port   = 8080
        to_port     = 8080
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }

}
Enter fullscreen mode Exit fullscreen mode

Terraform allows you to make your code more configurables hence aligns with the DRY Principle. We achieve this by defining input variables the syntax:

variable "<variable-name>" {
 [CONFIG ...]
}
Enter fullscreen mode Exit fullscreen mode

the body of a vriable contains the following parameters which are optional

  • description: used to document how the variable is used
  • default: used when no value is provided. if there is no value Terraform will prompt the user for one

There are multiple ways of providing a value for a variable i.e command line using -var option, via a file using the -var-file option, or via environment virable

  • type: allows you to enforce constraints on the variable
  • validation: allows you to dife custom validations rules for an input
  • sensitive: if set to true on an input it will not be logged when apply or plan are executed.

You can read more on this. For now let's proceed with the task at hand let's introduce our first variable. In this example we will define the default value

variable "server_port" {
    description = "The port the server will use for HTTP requests"
    type = number
    default = 8080
}
Enter fullscreen mode Exit fullscreen mode

In order to use this variable we will employ the use of terraform expressions called variable reference. it follows the syntax below:

var.<VARIABLE_NAME>

resource "aws_security_group" "instance" {
    name  = "mk-terraform-security-group"

    ingress {
        from_port   = var.server_port
        to_port     = var.server_port
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }

}

Enter fullscreen mode Exit fullscreen mode

Note in our User data script we also defined port 8080. We can reference the variable using and expression called an interpolation of syntax:

"${..........}"

OUTPUT VARIABLE

We if we can input for sure we can output. An output variable has the following syntax:

output "<NAME>" {
  value = <VALUE>
 [CONFIG ...]
}

Enter fullscreen mode Exit fullscreen mode

The Config contains the following optional parameters:

  • description: allows you to document the type of data contained in the output variable
  • sensitive: flags if data should be shown when plan or apply are executed
  • depends_on: allows you to create dependency between resources that require each other.

USE CASE:
Instead of having to manually poke around the EC2 console to get the IP address of your newly created server you can provide the IP address as an output variable

output "public_ip" {
    value = aws_instance.example.public_ip
    description = "The public IP address of the web server"
}

Enter fullscreen mode Exit fullscreen mode

When you run the Command terraform apply. you will see the output show up as seen in the screenshot below.

You can also use command terraform output to list all outputs without applying changes

mktowett@Kiprotichs-MacBook-Pro Day2 % terraform output
public_ip = "16.146.72.177"
mktowett@Kiprotichs-MacBook-Pro Day2 % 

Enter fullscreen mode Exit fullscreen mode

in the event you want a specific output you could always pass the name give to that output after the command above and it will print out the results

terraform output <output-name>

mktowett@Kiprotichs-MacBook-Pro Day2 % terraform output public_ip 
"16.146.72.177"
mktowett@Kiprotichs-MacBook-Pro Day2 % 

Enter fullscreen mode Exit fullscreen mode

Top comments (0)