This project combines Terraform for infrastructure automation and Docker for containerizing a simple Flask web application. You’ll create a basic Flask application, containerize it using Docker, and then use Terraform to provision an AWS EC2 instance, deploy the Docker container, and expose the Flask application over the web.
Project Overview
- Flask Application: A simple Flask web app.
- Docker: Containerize the app so it runs consistently on any machine.
- Terraform: Provision AWS resources to host the Dockerized application on an EC2 instance.
Steps to Set Up the Project
1. Create a Simple Flask Application with Docker
- Create a New Directory: This will be your project folder. 
- Create the Flask Application ( - app.py):
 In your project folder, create a file called- app.pywith the following content:
 
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return "Hello, world from Flask in Docker on AWS!"
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
This Flask application simply returns a "Hello World" message when you access the root URL.
- 
Create a Dockerfile: 
In the same directory, create a Dockerfileto containerize the Flask application.
# Use the official Python image
FROM python:3.9-slim
# Set the working directory
WORKDIR /app
# Copy the application files
COPY app.py /app
# Install Flask
RUN pip install Flask
# Run the application
CMD ["python", "app.py"]
The Dockerfile defines the environment for your Flask app and installs Flask inside the container.
2. Build and Test the Docker Image Locally
To ensure the app works locally, build and run the Docker image:
docker build -t flask-app .
docker run -p 5000:5000 flask-app
Now, open a browser and visit http://localhost:5000 to check if the Flask app is running locally.
3. Terraform configuration
Terraform configuration, including resource.tf, ec2.tf, main.tf, backend.tf, output.tf, and variables.tf, would look for deploying a Dockerized Flask app on an EC2 instance:
main.tf (Provider Configuration)
provider "aws" {
  region     = "us-west-2"
  access_key = "xxxxxxxxxxxxxxxxxxxxxx"
  secret_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
resource.tf (Network, VPC, Security Group, and Internet Gateway)
# VPC
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = {
    Name = "Project terraform"
  }
}
# Internet Gateway
resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "MainInternetGateway"
  }
}
# Route Table for Public Subnet
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }
  tags = {
    Name = "PublicRouteTable"
  }
}
# Subnet
resource "aws_subnet" "demosubnet" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.subnet_cidr
  availability_zone       = "us-west-2a"
  map_public_ip_on_launch = true
  tags = {
    Name = "Public Subnet"
  }
}
# Associate the Route Table with the Public Subnet
resource "aws_route_table_association" "public_subnet" {
  subnet_id      = aws_subnet.demosubnet.id
  route_table_id = aws_route_table.public.id
}
# Security Group
resource "aws_security_group" "allow_http" {
  name        = "allow_http_${random_id.unique_id.hex}"  # Use a random ID to make the name unique
  description = "Allow HTTP traffic"
  vpc_id      = aws_vpc.main.id
  # Ingress rule to allow HTTP traffic
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 5000
    to_port     = 5000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  # Egress rule to allow all outbound traffic
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = "AllowHTTP"
  }
}
resource "random_id" "unique_id" {
  byte_length = 4
}
ec2.tf (EC2 Configuration to Run Flask App)
# EC2 Instance
resource "aws_instance" "flask_ec2" {
  ami           = var.ami_id
  instance_type = var.instance_type
  vpc_security_group_ids = [aws_security_group.allow_http.id]  # Dynamically use created security group ID
  subnet_id     = var.public_subnet_id
  associate_public_ip_address = true
  user_data = <<-EOF
              #!/bin/bash
              # Update the system
              yum update -y
              # Install Docker manually (alternative to amazon-linux-extras)
              yum install -y docker
              # Start Docker service
              service docker start
              # Enable Docker service on boot
              service docker enable
              # Add ec2-user to Docker group
              usermod -a -G docker ec2-user
              # Run the Flask app container
              docker run -d -p 5000:5000 nadasaad/flask-app:latest
            EOF
  tags = {
    Name = "FlaskDockerEC2"
  }
  depends_on = [aws_security_group.allow_http]  # Ensure security group is created first
}
backend.tf (Backend Configuration for Terraform State)
terraform {
  backend "s3" {
    bucket         = "mybucket09a"
    key            = "terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "lockstate"
  }
}
output.tf (Outputs for Public IP)
output "public_ip" {
  value = aws_instance.flask_ec2.public_ip
}
variables.tf (Variable Definitions)
variable "ami_id" {
  description = "The AMI ID to use for the EC2 instance"
  default     = "ami-066a7fbea5161f451"  # Replace with the correct AMI ID for your region
}
variable "instance_type" {
  description = "The type of instance to use for the EC2 instance"
  default     = "t2.micro"  # Modify as needed
}
variable "subnet_cidr" {
  description = "The CIDR block for the subnet"
  default     = "10.0.1.0/24"  # Modify as needed
}
variable "security_group_id" {
  description = "The security group ID to associate with EC2 instance"
  default     = "sg-06e61ad57b5d3d5d0"  # Modify with your security group ID
}
variable "public_subnet_id" {
  description = "The subnet ID where EC2 will be created"
  default     = "subnet-0f84f2821d4f682bb"  # Modify with your subnet ID
}
Explanation:
- Security Group: Allows inbound traffic on port 5000 for HTTP and port 22 for SSH.
- EC2 Instance: Launches an EC2 instance with Docker installed using a user-data script that also runs the Flask app in a Docker container.
Replace:
- 
your_vpc_idwith your actual VPC ID.
- 
your_key_pair_namewith your EC2 key pair name.
- 
your_dockerhub_usernamewith your Docker Hub username.
4. Push the Docker Image to Docker Hub
Before Terraform can deploy the Flask app to the EC2 instance, you need to push the Docker image to a registry (such as Docker Hub).
- Tag the Docker Image:
   docker tag flask-app your_dockerhub_username/flask-app:latest
- Push the Image to Docker Hub:
   docker push your_dockerhub_username/flask-app:latest
Make sure your Docker Hub account is logged in using docker login.
5. Deploy the Project with Terraform
Now, let’s deploy the resources with Terraform:
- Initialize the Terraform Configuration:
   terraform init
- Apply the Terraform Configuration:
   terraform apply
Terraform will prompt you for confirmation before provisioning the infrastructure. Type yes to proceed. It will then create an EC2 instance, security group, and other necessary resources.
6. Access Your Flask Application
Once the Terraform apply is successful, it will output the public IP of the EC2 instance.
- Obtain the EC2 Public IP: You can find it in the Terraform output or AWS Management Console.
- Access the Flask App: Open a web browser and go to:
   http://<EC2_PUBLIC_IP>:5000
Replace <EC2_PUBLIC_IP> with the actual public IP of your EC2 instance. You should see the message "Hello, world from Flask in Docker on AWS!" displayed in the browser.
Conclusion
In this project, we successfully:
- Created a simple Flask web application.
- Containerized the application with Docker.
- Used Terraform to provision AWS infrastructure and deploy the Dockerized app to an EC2 instance.
- Ensured the app was accessible via a public IP.
By combining Docker for containerization and Terraform for infrastructure automation, we can deploy applications consistently and efficiently in the cloud.
This project can be expanded further by adding more complex applications, integrating databases, and setting up monitoring solutions to make it a fully-featured production environment.
 
 
              







 
 
    
Top comments (0)