How to deploy an EC2 instance in AWS with Terraform

.

  • How to install terraform
  • How to configure your aws cli
  • How to steup your file structure
  • How to deploy your instance
  • You must have an AWS account already setup
    • You have an existing VPC
    • You have existing security groups

Depending on which machine you like to use. I use varied distros for fun.

For this we will use Ubuntu 22.04

How to install terraform

  • Once you are logged into your linux jump box or whatever you choose to manage.

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg –dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo “deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt update && sudo apt install terraform

.

ThanosJumpBox:~/myterraform$ terraform -v

Terraform v1.8.2

on linux_amd64

+ provider registry.terraform.io/hashicorp/aws v5.47.

  • Okay next you want to install the awscli

sudo apt update

sudo apt install awscli

2. Okay Now you need to go into your aws and create a user and aws cli key

  • Log into your aws console
  • Go to IAM
    • Under users create a user called Terrform-thanos

Next you want to either create a group or add it to an existing. To make things easy for now we are going to add it administrator group

Next click on the new user and create the ACCESS KEY

Next select the use case for the key

Once you create the ACCESS-KEY you will see the key and secret

Copy these to a text pad and save them somewhere safe.

Next you we going to create the RSA key pair

  • Go under EC2 Dashboard
  • Then Network & ecurity
  • Then Key Pairs
  • Create a new key pair and give it a name

Now configure your Terrform to use the credentials

thanosjumpbox-myterraform$ aws configure

AWS Access Key ID [****************RKFE]:

AWS Secret Access Key [****************aute]:

Default region name [us-west-1]:

Default output format [None]:

.

So a good terraform file structure to use in work environment would be

my-terraform-project/

├── main.tf

├── variables.tf

├── outputs.tf

├── provider.tf

├── modules/

   ├── vpc/

      ├── main.tf

      ├── variables.tf

      └── outputs.tf

   └── ec2/

       ├── main.tf

       ├── variables.tf

       └── outputs.tf

├── environments/

   ├── dev/

      ├── main.tf

      ├── variables.tf

      └── outputs.tf

   ├── prod/

      ├── main.tf

      ├── variables.tf

      └── outputs.tf

├── terraform.tfstate

├── terraform.tfvars

└─ .gitignore

That said for the purposes of this post we will keep it simple. I will be adding separate posts to deploy vpc’s, autoscaling groups, security groups etc.

This would also be very easy to display if you VSC to connect to your
linux machine

mkdir myterraform

cd myterraform

touch main.tf outputs.tf variables.tf

.

So we are going to create an Instance as follows

 EC2 in my existing VPC
 Using a AMI Amazon Linux 2023 AMI (AMI CATALOG will have the ID)
 ami-0827b6c5b977c020e (ID)
 t2.micro instance type
 using a subnet that is available in the us-west-1 zone available for my vpc
 You can find the ID in the console VPC-subnets
 Security groups again will be found under Network & Security > Security Groups
 Use a general purpose volume 30G SSD
 Which is using a custom security group I created earlier
 The outputs will provided via the outputs.tf

Main.tf

provider “aws” {

  region = var.region

}

.

resource “aws_instance” “my_instance” {

  ami           = “ami-0827b6c5b977c020e  # Use a valid AMI ID for your region

  instance_type = “t2.micro              # Free Tier eligible instance type

  key_name      = “”           # Ensure this key pair is already created in your AWS account

.

  subnet_id              = “subnet-0e80683fe32a75513  # Ensure this is a valid subnet in your VPC

  vpc_security_group_ids = [“sg-0db2bfe3f6898d033]  # Ensure this is a valid security group ID

.

  tags = {

    Name = “thanos-lives”

  }

.

  root_block_device {

    volume_type = “gp2  # General Purpose SSD, which is included in the Free Tier

    volume_size = 30     # Maximum size covered by the Free Tier

  }

.

Outputs.tf

output “instance_ip_addr” {

  value = aws_instance.my_instance.public_ip

  description = “The public IP address of the EC2 instance.”

}

.

output “instance_id” {

  value = aws_instance.my_instance.id

  description = “The ID of the EC2 instance.”

}

.

output “first_security_group_id” {

  value = tolist(aws_instance.my_instance.vpc_security_group_ids)[0]

  description = “The first Security Group ID associated with the EC2 instance.”

}

.

Variables.tf

variable “region” {

  description = “The AWS region to create resources in.”

  default     = “us-west-1”

}

.

variable “ami_id” {

  description = “The AMI ID to use for the server.”

}

.

.

Terraform.tfsvars

region = “us-west-1”

ami_id = “ami-0827b6c5b977c020e  # Replace with your chosen AMI ID

.

.

Deploying your code:

thanosjumpbox:~/my-terraform$ terraform init

.

Initializing the backend…

.

Initializing provider plugins…

Reusing previous version of hashicorp/aws from the dependency lock file

Using previously-installed hashicorp/aws v5.47.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.

thanosjumpbox:~/my-terraform$ terraform$

.

thanosjumpbox:~/my-terraform$ terraform$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:

  + create

.

Terraform will perform the following actions:

.

  # aws_instance.my_instance will be created

  + resource “aws_instance” “my_instance” {

      + ami                                  = “ami-0827b6c5b977c020e”

      + arn                                  = (known after apply)

      + associate_public_ip_address          = (known after apply)

      + availability_zone                    = (known after apply)

      + cpu_core_count                       = (known after apply)

      + cpu_threads_per_core                 = (known after apply)

      + disable_api_stop                     = (known after apply)

      + disable_api_termination              = (known after apply)

      + ebs_optimized                        = (known after apply)

      + get_password_data                    = false

      + host_id                              = (known after apply)

      + host_resource_group_arn              = (known after apply)

      + iam_instance_profile                 = (known after apply)

      + id                                   = (known after apply)

      + instance_initiated_shutdown_behavior = (known after apply)

      + instance_lifecycle                   = (known after apply)

      + instance_state                       = (known after apply)

      + instance_type                        = “t2.micro

      + ipv6_address_count                   = (known after apply)

      + ipv6_addresses                       = (known after apply)

      + key_name                             = “nicktailor-aws”

      + monitoring                           = (known after apply)

      + outpost_arn                          = (known after apply)

      + password_data                        = (known after apply)

      + placement_group                      = (known after apply)

      + placement_partition_number           = (known after apply)

      + primary_network_interface_id         = (known after apply)

      + private_dns                          = (known after apply)

      + private_ip                           = (known after apply)

      + public_dns                           = (known after apply)

      + public_ip                            = (known after apply)

      + secondary_private_ips                = (known after apply)

      + security_groups                      = (known after apply)

      + source_dest_check                    = true

      + spot_instance_request_id             = (known after apply)

      + subnet_id                            = “subnet-0e80683fe32a75513”

      + tags                                 = {

          + “Name” = “Thanos-lives”

        }

      + tags_all                             = {

          + “Name” = “Thanos-lives”

        }

      + tenancy                              = (known after apply)

      + user_data                            = (known after apply)

      + user_data_base64                     = (known after apply)

      + user_data_replace_on_change          = false

      + vpc_security_group_ids               = [

          + “sg-0db2bfe3f6898d033”,

        ]

.

      + root_block_device {

          + delete_on_termination = true

          + device_name           = (known after apply)

          + encrypted             = (known after apply)

          + iops                  = (known after apply)

          + kms_key_id            = (known after apply)

          + tags_all              = (known after apply)

          + throughput            = (known after apply)

          + volume_id             = (known after apply)

          + volume_size           = 30

          + volume_type           = “gp2”

        }

    }

.

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

.

Changes to Outputs:

  + first_security_group_id = “sg-0db2bfe3f6898d033”

  + instance_id             = (known after apply)

  + instance_ip_addr        = (known after apply)

.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

.

Note: You didn’t use the -out option to save this plan, so Terraform can’t guarantee to take exactly these actions if you run “terraform

apply” now.

.

thanosjumpbox:~/my-terraform$ terraform$ terraform apply

.

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:

  + create

.

Terraform will perform the following actions:

.

  # aws_instance.my_instance will be created

  + resource “aws_instance” “my_instance” {

      + ami                                  = “ami-0827b6c5b977c020e”

      + arn                                  = (known after apply)

      + associate_public_ip_address          = (known after apply)

      + availability_zone                    = (known after apply)

      + cpu_core_count                       = (known after apply)

      + cpu_threads_per_core                 = (known after apply)

      + disable_api_stop                     = (known after apply)

      + disable_api_termination              = (known after apply)

      + ebs_optimized                        = (known after apply)

      + get_password_data                    = false

      + host_id                              = (known after apply)

      + host_resource_group_arn              = (known after apply)

      + iam_instance_profile                 = (known after apply)

      + id                                   = (known after apply)

      + instance_initiated_shutdown_behavior = (known after apply)

      + instance_lifecycle                   = (known after apply)

      + instance_state                       = (known after apply)

      + instance_type                        = “t2.micro

      + ipv6_address_count                   = (known after apply)

      + ipv6_addresses                       = (known after apply)

      + key_name                             = “nicktailor-aws”

      + monitoring                           = (known after apply)

      + outpost_arn                          = (known after apply)

      + password_data                        = (known after apply)

      + placement_group                      = (known after apply)

      + placement_partition_number           = (known after apply)

      + primary_network_interface_id         = (known after apply)

      + private_dns                          = (known after apply)

      + private_ip                           = (known after apply)

      + public_dns                           = (known after apply)

      + public_ip                            = (known after apply)

      + secondary_private_ips                = (known after apply)

      + security_groups                      = (known after apply)

      + source_dest_check                    = true

      + spot_instance_request_id             = (known after apply)

      + subnet_id                            = “subnet-0e80683fe32a75513”

      + tags                                 = {

          + “Name” = “Thanos-lives”

        }

      + tags_all                             = {

          + “Name” = “Thanos-lives”

        }

      + tenancy                              = (known after apply)

      + user_data                            = (known after apply)

      + user_data_base64                     = (known after apply)

      + user_data_replace_on_change          = false

      + vpc_security_group_ids               = [

          + “sg-0db2bfe3f6898d033”,

        ]

.

      + root_block_device {

          + delete_on_termination = true

          + device_name           = (known after apply)

          + encrypted             = (known after apply)

          + iops                  = (known after apply)

          + kms_key_id            = (known after apply)

          + tags_all              = (known after apply)

          + throughput            = (known after apply)

          + volume_id             = (known after apply)

          + volume_size           = 30

          + volume_type           = “gp2”

        }

    }

.

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

.

Changes to Outputs:

  + first_security_group_id = “sg-0db2bfe3f6898d033”

  + instance_id             = (known after apply)

  + instance_ip_addr        = (known after apply)

.

Do you want to perform these actions?

  Terraform will perform the actions described above.

  Only ‘yes’ will be accepted to approve.

.

  Enter a value: yes

.

aws_instance.my_instance: Creating…

aws_instance.my_instance: Still creating… [10s elapsed]

aws_instance.my_instance: Still creating… [20s elapsed]

aws_instance.my_instance: Creation complete after 22s [id=i-0ee382e24ad28ecb8]

.

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

.

Outputs:

.

first_security_group_id = “sg-0db2bfe3f6898d033”

instance_id = “i-0ee382e24ad28ecb8”

instance_ip_addr = “50.18.90.217”

Result:

Leave a Reply

Your email address will not be published. Required fields are marked *

0