1. Objective
The objective of this project was to deploy a complete and functional full-stack web application, composed of a frontend (Nginx/HTML), a backend (Flask/Python), and a database (MySQL). The entire architecture was containerized using Docker and deployed on an AWS infrastructure.
2. AWS Infrastructure Architecture
The AWS architecture was configured to route traffic securely and in a controlled manner to the application.
A CloudFront distribution was deployed to receive all public user traffic. This distribution is configured to forward requests to a single EC2 instance.
The EC2 instance serves as the host where the Docker environment runs. To control access, a Security Group was configured to act as a firewall, allowing incoming TCP traffic only on ports 8090 (frontend) and 5001 (backend API). The remaining ports, including the database port, are not accessible from the internet.
3. Container Architecture (Docker)
The application was broken down into three independent but interconnected services, each with its own container, orchestrated within the EC2 instance.
- Frontend (Nginx):
- Base Image:
nginx:stable-alpine
. - Function: Serves the static
index.html
file. This file contains the JavaScript code that makes calls to the backend API.
- Base Image:
- Backend (Flask):
- Base Image:
python:3.9
. - Function: Exposes a RESTful API (
/tasks
) to manage tasks. It processes requests from the frontend and communicates with the database.
- Base Image:
- Database (MySQL):
- Base Image:
mysql:8.0
. - Function: Stores task data in a persistent Docker volume. It is initialized with the
tasks
table required by the application.
- Base Image:
- Docker Network (
mi-app
):- A private virtual network that connects the containers. It allows the backend to communicate with the database by its service name (
mysql-db
) in an isolated and secure manner.
- A private virtual network that connects the containers. It allows the backend to communicate with the database by its service name (
4. Deployment and Execution on EC2
Once the infrastructure was provisioned, the deployment on the EC2 instance was performed with the following commands, executed in the correct order to respect dependencies.
Create the Network and Persistent Volume:
Bashdocker network create mi-app docker volume create db_data
Build the Custom Images:
Bash# Build the backend image docker build -t backend-app ./backend # Build the frontend image docker build -t frontend-app ./frontend
Run the Containers:
Bash# 1. Start the database docker run --name mysql-db --network mi-app -v db_data:/var/lib/mysql -v "$(pwd)/db/init.sql:/docker-entrypoint-initdb.d/init.sql" -e MYSQL_ROOT_PASSWORD=contraseña -e MYSQL_DATABASE=DB -e MYSQL_USER=user -e MYSQL_PASSWORD=contraseña -d mysql:8.0 # 2. Start the backend, connecting it to the database docker run --name backend-container --network mi-app -p 5001:5000 -e DB_HOST=mysql-db -e DB_USER=user -e DB_PASSWORD=contraseña -e DB_NAME=DB -d backend-app # 3. Start the frontend docker run --name frontend-container --network mi-app -p 8080:80 -d frontend-app
5. Verifying Functionality
The success of the deployment is verified by following the complete application flow:
- Access: The application is accessed via the public CloudFront URL (or
http://<PUBLIC_IP>:8090
for direct testing). - Initial Load: The frontend (Nginx) serves the
index.html
file. The page’s JavaScript makes aGET
request to the backend (http://<PUBLIC_IP>:5001/tasks
), which in turn queries the database and returns the initial tasks. - Interaction: When adding a new task, the frontend sends a
POST
request to the backend. The backend processes it, inserts it into the database via the internalmi-app
network, and the frontend updates the view to display the new task.
