Terraform Tutorial: How to Create and Manage Infrastructure


To easily and safely create, manage, and destroy infrastructure resources such as compute instances, storage, or DNS, you can save time (and money) using Terraform, an open-source infrastructure automation tool. Terraform is a very flexible tool that works with a variety of cloud providers, including Google Cloud, DigitalOcean, Azure, AWS, and more. Terraform enables infrastructure-as-code using a declarative and simple programming language and powerful CLI commands. Within this series, we’ll use Terraform to create resources on AWS. Within this specific Terraform tutorial, I’ll explain the basic syntax modules and share a few best practices I’ve learned along the way. 


A Closer Look at the Infrastructure We’ll Create

First, let’s review the resources and infrastructure we’ll create within this Terraform series:

1. Virtual private cloud (VPC): I want to have our cluster inside a VPC because I want to take over networking and security in my infrastructure.

2. Application Load Balancer: It redirects and balances the traffic to my ECS cluster.

3. Public and private subnets.

4. ECS: A cluster based on EC2 instances. Here we will create tasks and services to deploy our containers.

5. Auto Scaling group: Our ECS cluster needs to scale up and down.

6. Amazon CloudWatch: This enables us to store and show Docker container logs. We’ll also use it to create alerts that warn of CPU and memory leaks. 


ECS Cluster


What Is Infrastructure-As-Code?

In my own words, infrastructure-as-code (IaC) means you can manage and configure your IT infrastructure using configuration files. IaC treats infrastructure setup as code to configure software and hardware rather than it being a manual process. For example, you could create a Virtual Machine on AWS using just a few lines of code. You can read more about IaC here


What is Terraform?

Terraform is an IaC tool that lets you build, change, and version infrastructure safely and efficiently. In addition, it has great documentation.

Terraform supports different cloud providers such as Alibaba, AWS, GCP, Microsoft Azure, PaaS, and more. Each provider exposes its own API interactions and resources. Think of a resource like a VM, VPC, Subnet, Cluster, etc.  


Terraform Tutorial Kick-Off: Install and Configure

To install Terraform:

1. Find the package for your system here and download it. Terraform is packaged as a zip archive. 

2. Unzip the package. Terraform runs as a single binary named terraform.  

3. Make sure that the terraform binary is available on the PATH.

4. Make sure that Terraform was configured correctly using the following command on your terminal console:


You should see the following console’s output after running the above command:

$ terraform
Usage: terraform [--version] [--help]  [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
# ...

5. If you don’t have an AWS account, create an AWS free-tier account.

a. For this Terraform tutorial, we will create our infrastructure in AWS (remember that, although it’s not the focus of this blog, Terraform can manage many providers, and can also handle multiple providers in a single configuration). 

6. The next step is to configure (or create, if it doesn’t exist) the AWs credentials file named “~/.aws/credentials” (Mac OS or Linux) or “%UserProfile%\.aws\credentials” on a Windows system (there you must put your AWS credentials): 

aws_access_key_id = 
aws_secret_access_key =

NOTE: You should never put your credentials in the Terraform’s code, remember that your credentials are private, keep that in mind. 

7. Create a workspace. For this Terraform tutorial, I will name the workspace “terraform-ecs-workshop”. 

8. Move into your new workspace and create the next three files with “tf” extension (Terraform extension):

Terraform tutorial, create files

• main.tf: Code to create our resources and infrastructure. 

• variables.tf: Variables that will act as parameters for the main.tf file. 

• outputs.tf: Anything we might want returned from the resources created. For example: resource name, ID, and so on. This makes it possible to use a value returned as a parameter for another function later.

Important concept: These three files together act much like a module or a function in a programming language. Terraform works with modules, because modules make it possible to reuse code. A module is a resource that you, and other developers on your team, could share and reuse when you need that same functionality. Terraform has its own modules, and they’re organized by provider. For example, the most common VPC module in AWS can be found here. We’ll use this module later to create a VPC. I love coding, but I want to reduce writing code whenever I can. Remember, apply the DRY concept (Don’t Repeat Yourself ) as much as you can and always think about how you can reuse code.

9. Now let’s configure things. Go to the variables file and enter the following:

variable "region" {
   type = string
   description = "Region where we will create our resources"
   default     = "us-east-1"

#Availability zones
variable "azs" {
  type = list(string)
  description = "Availability zones"

We’ve defined two variables: the region and the availability zone(s) we want to use. 

We must declare the format of a variable using a variable block, like this:

variable "example" {
 type: Type of value for the variable. More info here
 description: Documentation of the variable.
 default: Value per default of the variable.

Important concept: I highly recommend using variables with attributes. By defining a type, you restrict the content of your variable. This makes your code easier to read and understand for other developers. 

In addition, the default attribute tells you: “I am an optional variable. If you don’t assign me to anything, I assume you want to use my default value.”  Use this attribute if you want your variable to use the default attribute. 

10. Go to the main.tf file:

provider "aws" {
 profile    = "default"
 region     = var.region

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "my-vpc"
  cidr = ""

  azs             = var.azs
  private_subnets = ["", ""]
  public_subnets  = ["", ""]

  enable_nat_gateway = true

  tags = {
    Terraform = "true"
    Environment = "dev"

The provider attribute defines which cloud provider Terraform will use. In our case, our provider is AWS.

The module attribute imports all the functionality of one specific module. For us, this is the VPC’s Terraform module. We’re setting the parameters the module needs to create a VPC. I always read the documentation for each module so I can be sure to understand them.  

Important: You can use either remote modules or your own local modules. Using the “source” parameter lets you define the module’s location.

11. Finally, create the VPC on AWS. Run the “terraform init” command in the same directory as the main.tf file you created (this initializes various local settings and data for subsequent commands).

terraform init
Initializing modules...
Downloading terraform-aws-modules/vpc/aws 2.17.0 for vpc...
- vpc in .terraform/modules/vpc/terraform-aws-modules-terraform-aws-vpc-5358041

Initializing the backend...

12. After creating the resources, you can see how many resources you can create by using the plan command:

  Availability zones

  Enter a value: ["us-east-1a","us-east-1b"]

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.


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.vpc.aws_eip.nat[0] will be created
  + resource "aws_eip" "nat" {
      + allocation_id     = (known after apply)
      + association_id    = (known after apply)
      + domain            = (known after apply)
      + id                = (known after apply)
      + instance          = (known after apply)
      + network_interface = (known after apply)
      + private_dns       = (known after apply)
      + private_ip        = (known after apply)
      + public_dns        = (known after apply)
      + public_ip         = (known after apply)
      + public_ipv4_pool  = (known after apply)
      + tags              = {
          + "Environment" = "dev"
          + "Name"        = "my-vpc-us-east-1a"
          + "Terraform"   = "true"
      + vpc               = true

    # module.vpc.aws_vpc.this[0] will be created
  + resource "aws_vpc" "this" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = false
      + cidr_block                       = ""
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = (known after apply)
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = false
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = "default"
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
      + tags                             = {
          + "Environment" = "dev"
          + "Name"        = "my-vpc"
          + "Terraform"   = "true"

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


Note: After you run the “terraform plan” command, check for the console input shown below.

  Availability zones

  Enter a value:

Terraform is asking you for the azs variable. (This variable is a zone list. In this example, I used [“us-east-1a”,”us-east-1b”]). This variable is not optional like region. Since we did not assign any value to the region variable, Terraform will use its default value.

13. Now run the “terraform apply”  command to create your resources. Terraform will ask for the azs variable again. It will also ask:

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

Enter yes. If all is good, you should see a message like this:

Apply complete! Resources: 20 added, 0 changed, 0 destroyed.

14. Go to AWS console -> VPC -> Your VPC.  You should see “my-vpc” resource created.


Wrapping up and Getting Ready for What’s Next

Congratulations, you just completed part one of this Terraform tutorial! You used Terraform to create one resource on AWS and you also learned about Terraform’s basic syntax and modules. In the next blog, we’ll continue to create new infrastructure resources, just as easily and safely as we did this first one.  In the meantime, you can continue to explore the infrastructure we just created. (Note that you can destroy resources, you can use the “terraform destroy” command. Easy as that!)


Subscribe to our Blog

Gorilla Logic

Gorilla Logic provides Agile teams for your most critical projects, bringing unparalleled expertise in delivery of full stack web, mobile and enterprise apps.

Related Articles

Ready to be Unstoppable?

Partner with Gorilla Logic, and you can be.