Deploy an App using Terraform in AWS

Deploy an App using Terraform in AWS

In this blog, we will deploy an application in the AWS using the terraform. In this demo, a simple Python project will be deployed and run using Terraform. The application is simple and easy. We will be provisioning the different commands to run the application.

We will copy the application code using file provision. The file provisioner is used to copy files or directories from the local machine to a remote machine. This is useful for deploying configuration files, scripts, or other assets to a provisioned instance.

The remote-exec provisioner is used to run scripts or commands on a remote machine over SSH connections. It's often used to configure or install software on provisioned instances.

Let's do it hands-on

We will create a simple Python application named "app.py"

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, Terraform from DevOps Learner!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80)

We created a simple Python application using the Flask framework. When it is executed, "Hello, Terraform from DevOps Learner!" will be printed in the browser.

Our application code is ready. Now let's provision the resources in the AWS.

Let's create the Terraform code "main.tf"

Define the AWS provider configuration and all the resources that need to be created are explained in each block of code. We will merge these code at the end in the main.tf file.

provider "aws" {
  region = "us-east-1"  # Replace with your desired AWS region.
}

variable "cidr" {
  default = "10.0.0.0/16"
}

We provided the provider where we needed to create the resources. In this case, we have chosen the "aws" and the variable has a default value of "10.0.0.0/16," which represents the CIDR block for the VPC (Virtual Private Cloud).

Create key-pair

resource "aws_key_pair" "example" {
  key_name   = "terraform-demo-subash"  # Replace with your desired key name
  public_key = file("~/.ssh/id_rsa.pub")  # Replace with the path to your public key file
}

This block of code will create the key-pair file for the instance that is stored on our local machine.

  • create VPC
resource "aws_vpc" "myvpc" {
  cidr_block = var.cidr
}

In this block of code, the vpc will be created with the cidr that is declared in the variable block i.e 10.0.0.0/16.

  • Create Subnet
resource "aws_subnet" "sub1" {
  vpc_id                  = aws_vpc.myvpc.id
  cidr_block              = "10.0.0.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true
}

In this block of code, a subnet will be create with the single availabiltity zone.

  • Create InternetGateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.myvpc.id
}

This block creates an internet gateway and associates it with the VPC.

  • Create Route Table
resource "aws_route_table" "RT" {
  vpc_id = aws_vpc.myvpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
}

This block creates a route table and adds a default route directing traffic to the internet gateway.

  • Route Table Association
resource "aws_route_table_association" "rta1" {
  subnet_id      = aws_subnet.sub1.id
  route_table_id = aws_route_table.RT.id
}

This block associates the subnet with the above route table.

  • Creating the security configuration
resource "aws_security_group" "webSg" {
  name   = "web"
  vpc_id = aws_vpc.myvpc.id

  ingress {
    description = "HTTP from VPC"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "Web-sg"
  }
}

The ingress is used to configure the inbound configuration for the instance, we have added two security rules one for SSH and the other for TCP to serve the application. Egress is used to configure the outbound configuration for the instance

  • Creating the ec2 instance
resource "aws_instance" "server" {
  ami                    = "ami-0261755bbcb8c4a84"
  instance_type          = "t2.micro"
  key_name      = aws_key_pair.example.key_name
  vpc_security_group_ids = [aws_security_group.webSg.id]
  subnet_id              = aws_subnet.sub1.id
  • Connecting to the ec2-instance
 connection {
    type        = "ssh"
    user        = "ubuntu"  # Replace with the appropriate username for your EC2 instance
    private_key = file("~/.ssh/id_rsa")  # Replace with the path to your private key
    host        = self.public_ip
  }
  • File provision code

File provisioner to copy a file from local to the remote EC2 instance

 provisioner "file" {
    source      = "app.py"  # Replace with the path to your local file
    destination = "/home/ubuntu/app.py"  # Replace with the path on the remote instance
  }
  • Provision code
provisioner "remote-exec" {
    inline = [
      "echo 'Hello from the remote instance'",
      "sudo apt update -y",  # Update package lists (for ubuntu)
      "sudo apt-get install -y python3-pip",  # Example package installation
      "cd /home/ubuntu",
      "sudo pip3 install flask",
      "sudo python3 app.py &",
    ]
  }
}

Now we will merge all code and apply the terraform commands.

Configure aws credentials

aws configure
terraform init
terraform plan

Here we will be creating the 8 resources.

terraform apply

g

All the resources are created successfully in our AWS account.

To list the resources created

terraform show

The instance is created and lets verify whether the app is running not.Copy the ip address of the instance and SSH into the instance.

ssh -i ~/.ssh/id_rsa ubuntu@public_ip

Our app is inside the ec2 instance and the python3 is also installed but the application is not running. Since we had added "&" at the end of the code and this code takes more time than the normal one so the terraform exits the process and moves to the other processes.

sudo python3 app.py

Great!! Our application is successfully deployed using the Terraform.

Delete the resources

terraform destroy

Throughout the entire blog, we covered the essential steps of creating AWS resources, including a VPC, subnet, security group, and EC2 instance, all orchestrated through Terraform's Infrastructure-as-Code (IaC) capabilities. The use of variables enhances flexibility, and the file and remote-exec provisioners enabled the smooth deployment of both infrastructure and application code.
Happy Learning!!