Deploying a Web Application with Terraform and Packer on AWS

Brittney Carr
5 min readApr 6, 2023

--

In this tutorial, we will walk you through the process of deploying a web application on AWS using Terraform and Packer. This will showcase how to create custom Amazon Machine Images (AMIs) using Packer, and then use Terraform to create and manage infrastructure resources. By the end of this tutorial, you will have a better understanding of how to use Terraform and Packer to create Infrastructure as Code (IaC) solutions.

Prerequisites:

  • Basic knowledge of AWS
  • Familiarity with Terraform and Packer
  • AWS account
  • Installed and configured AWS CLI, Terraform, and Packer on your local machine

Step 1: Develop a Basic Web Application

  1. Create a new directory for your Flask project and navigate to it in your terminal.
  2. Create a virtual environment for your project (optional but recommended) to isolate dependencies:
python3 -m venv venv

3. Activate the virtual environment:

For Linux and macOS:

source venv/bin/activate

For Windows:

.\venv\Scripts\activate

4. Install Flask using pip:

pip install flask

5. Create a new file named app.py and add the following code:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)

6. Test your Flask application by running python app.py in the terminal. Open a web browser and visit http://localhost:8080 to ensure the "Hello, World!" page is displayed.

Step 2: Create Custom Amazon Machine Images (AMIs) with Packer

  1. Create a directory for your Packer project and navigate to it in your terminal.
  2. Create a Packer template file named packer.json. This file will contain the configuration for creating a custom Amazon Machine Image (AMI) based on an existing base image.
  3. Add the following code to your packer.json file:
{
"variables": {
"aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
"aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}"
},
"builders": [
{
"type": "amazon-ebs",
"access_key": "{{user `aws_access_key`}}",
"secret_key": "{{user `aws_secret_key`}}",
"region": "us-west-2",
"source_ami_filter": {
"filters": {
"virtualization-type": "hvm",
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
"root-device-type": "ebs"
},
"owners": ["099720109477"],
"most_recent": true
},
"instance_type": "t2.micro",
"ssh_username": "ubuntu",
"ami_name": "web-app-{{timestamp}}"
}
],
"provisioners": [
{
"type": "shell",
"inline": [
"sudo apt-get update",
"sudo apt-get upgrade -y",
"sudo apt-get install -y python3-pip",
"sudo pip3 install flask"
]
},
{
"type": "file",
"source": "../flask-app/app.py",
"destination": "/home/ubuntu/app.py"
},
{
"type": "shell",
"inline": [
"echo 'FLASK_APP=/home/ubuntu/app.py' | sudo tee -a /etc/environment",
"echo 'FLASK_RUN_HOST=0.0.0.0' | sudo tee -a /etc/environment",
"echo 'FLASK_RUN_PORT=8080' | sudo tee -a /etc/environment"
]
},
{
"type": "shell",
"inline": [
"sudo systemctl enable flaskapp.service"
]
}
]
}

4. In the builders section, customize the region, source_ami_filter, and instance_type as needed for your specific requirements.

5. In the provisioners section, the first block installs required software, such as Python 3, pip, and Flask. The second block copies the Flask application file (app.py) from your local machine to the remote instance. The third block sets environment variables for the Flask application. The fourth block (optional) enables the Flask application to run as a systemd service (ensure you have a flaskapp.service file in your Packer project directory).

6. Ensure that you have AWS CLI installed and configured with your AWS access key and secret key.

7. Run the following command in your terminal to build the custom AMI:

packer build packer.json

8. After the build process is completed, note the generated AMI ID from the terminal output. You will use this AMI ID in your Terraform configuration to deploy instances based on this custom image.

Step 3: Create Infrastructure Resources with Terraform

  1. Create a new directory for your Terraform project and navigate to it in your terminal.
  2. Initialize a Terraform project using terraform init.
  3. Create Terraform configuration files (main.tf, variables.tf, and outputs.tf) to create infrastructure resources on AWS, including VPC, subnets, security groups, load balancer, and compute instances based on the custom Amazon Machine Image (AMI) created in Step 2.

Example main.tf file:

provider "aws" {
region = var.aws_region
}

# VPC
resource "aws_vpc" "web_app_vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "web-app-vpc"
}
}

# Subnet
resource "aws_subnet" "web_app_subnet" {
vpc_id = aws_vpc.web_app_vpc.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "web-app-subnet"
}
}

# Security Group
resource "aws_security_group" "web_app_sg" {
name = "web-app-sg"
description = "Allow inbound traffic for web app"
vpc_id = aws_vpc.web_app_vpc.id

ingress {
from_port = 8080
to_port = 8080
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"]
}
}

# EC2 Instance
resource "aws_instance" "web_app" {
ami = var.web_app_ami_id
instance_type = "t2.micro"
key_name = var.key_pair_name

vpc_security_group_ids = [aws_security_group.web_app_sg.id]
subnet_id = aws_subnet.web_app_subnet.id

tags = {
Name = "web-app-instance"
}
}

Example variables.tf file:

variable "aws_region" {
default = "us-west-2"
}

variable "web_app_ami_id" {
description = "The AMI ID for the web application instance"
}

variable "key_pair_name" {
description = "The name of the key pair to use for the instance"
}

Example outputs.tf file:

output "aws_instance_public_ip" {
value = aws_instance.web_app.public_ip
}

4. Set the required variables in a terraform.tfvars file or provide them on the command line when running terraform apply. For example, your terraform.tfvars file may look like this:

web_app_ami_id = "ami-1234567890abcdef0"
key_pair_name = "your-key-pair"

5. Deploy your infrastructure using terraform apply. Review the changes and confirm when prompted.

Step 4: Testing Your Web Application

  1. After the infrastructure has been successfully deployed, retrieve the public IP address of your AWS instance from the Terraform output by running terraform output aws_instance_public_ip.
  2. Open a web browser and visit the public IP address followed by the port number (e.g., http://<public-ip>:8080). Verify that the web application is running on the AWS instance and displaying the "Hello, World!" page.

Conclusion:

In this tutorial, we embarked on a journey to deploy a simple web application on AWS using modern Infrastructure as Code (IaC) tools like Terraform and Packer. These powerful tools, when used effectively, can significantly streamline the process of creating, managing, and scaling infrastructure.

By mastering IaC tools and techniques, you can focus on the things that matter most — building and delivering incredible applications that delight users — while leaving the heavy lifting of infrastructure management to automation.

As you move forward, remember to explore additional features and integrations offered by Terraform and Packer, and continue to build on your IaC expertise. The ever-evolving world of cloud infrastructure awaits your creativity and innovation, so dive in and transform the way you manage and deploy your applications!

Happy coding and may the power of Infrastructure as Code be with you!

--

--

Brittney Carr
0 Followers

DevOps Engineer passionate about IaC, cloud computing, and automation. Sharing insights on Terraform, Packer, Kubernetes, and more. Connect & learn together!