🐳 Docker - Day 11 : Deploying a Two-Tier Flask Application on AWS EC2
Containerizing and Deploying a Flask App with Database on EC2

Cloud & DevOps enthusiast learning in public ☁️⚙️ Documenting my journey through systems, automation, and real-world engineering problems. Focused on fundamentals, practical learning, and continuous growth.
Docker + Docker Compose (Production-Style Walkthrough)
In this blog, we deploy a two-tier Todo application (Flask + MySQL) on an AWS EC2 instance using Docker and Docker Compose.
This day focuses on:
EC2 setup
Docker & Docker Compose installation
Building and pushing Docker images
Running a two-tier app using Docker Compose
1️⃣ Architecture Overview
Two-Tier Application Architecture
User
↓
Flask Application (Docker Container)
↓
MySQL Database (Docker Container)
App Tier → Flask (Python)
DB Tier → MySQL
Orchestration → Docker Compose
Hosting → AWS EC2
2️⃣ AWS EC2 Setup
🔹 Create EC2 Instance
AMI: Ubuntu 22.04
Instance type:
t2.micro/t3.microKey pair: Create or use existing
🔹 Security Group Rules
Allow inbound traffic on:
| Port | Purpose |
| 22 | SSH |
| 80 | HTTP |
| 443 | HTTPS |
| 5000 | Flask App |
📌 Outbound: Allow all
3️⃣ Connect to EC2 & Update System
ssh -i key.pem ubuntu@<EC2-PUBLIC-IP>
sudo apt update && sudo apt upgrade -y
4️⃣ Install Docker
sudo apt install docker.io -y
# Check
sudo systemctl status docker
# If needed
sudo systemctl start docker
sudo systemctl enable docker



🔹 Add User to Docker Group
# Create the docker group.
sudo groupadd docker
# Add your user to the docker group.
sudo usermod -aG docker $USER
# Activate the changes to groups
newgrp docker
Verify:
docker --version

5️⃣ Install Docker Compose
sudo apt install docker-compose -y

Verify:
docker-compose --version

6️⃣ Clone the Application Repository
git clone https://github.com/arvindhvetri/FlowList-DevOps-Deployment.git
cd FlowList-DevOps-Deployment

7️⃣ Dockerfile – Flask Application Image
📄 Dockerfile
# Use a lightweight Python base image to keep the final size small
FROM python:3.9-slim
# Set the working directory inside the container for all subsequent commands
WORKDIR /app
# Install system dependencies required for compiling mysqlclient
# We clean up apt logs afterward to reduce the image layer size
RUN apt-get update \
&& apt-get install -y gcc default-libmysqlclient-dev pkg-config \
&& rm -rf /var/lib/apt/lists/*
# Copy only requirements first to leverage Docker's build cache
COPY requirements.txt .
# Install Python dependencies and the MySQL driver for Python
RUN pip install --no-cache-dir -r requirements.txt mysqlclient
# Copy the rest of the application source code into the container
COPY . .
# Document that the container listens on port 8000
EXPOSE 8000
# Specify the default command to run your Flask or Django application
CMD ["python", "app.py"]
🔍 Dockerfile Explanation
🔹 Base Image
python:3.9-slimLightweight and production-friendly
🔹 System Dependencies
gcc,libmysqlclient-devRequired for building
mysqlclientPython package
🔹 Dependency Installation
requirements.txtcopied first for cachingReduces rebuild time
🔹 Application Code
Copied after dependencies
Follows Docker layer optimization best practice
🔹 CMD
- Starts Flask app using
pythonapp.py
📌 This image is generic, reusable, and production-aligned.
8️⃣ Build Docker Image
docker build -t arvindh01/todolist-app:latest .

Verify:
docker images

9️⃣ Docker Login & Push Image to Docker Hub
🔹 Login
docker login -u your_username
Enter:
Docker Hub username
Password / token
🔹 Push Image
docker push arvindh01/todolist-app:latest
📌 Image is now available globally and reusable in Compose.
🔟 Docker Compose – Two-Tier Application
📄 docker-compose.yml
version: "3.8"
services:
mysql:
image: mysql:5.7
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: admin
MYSQL_DATABASE: tododb
volumes:
- ./mysql-data:/var/lib/mysql
- ./table.sql:/docker-entrypoint-initdb.d/table.sql
networks:
- twotier
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-padmin"]
interval: 10s
timeout: 5s
retries: 5
start_period: 60s
flask-app:
image: arvindh01/todolist-app:latest # Dockerhub Image : 2tier-todoapp
container_name: todoapp
ports:
- "5000:8000"
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: admin
MYSQL_DB: tododb
depends_on:
mysql:
condition: service_healthy
networks:
- twotier
restart: always
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
twotier:
driver: bridge
1️⃣1️⃣ Docker Compose Explanation
🔹 MySQL Service
Uses official MySQL 5.7 image
Initializes DB + tables automatically
Data persisted using volumes
Health check ensures DB readiness
🔹 Flask App Service
Pulls image from Docker Hub
Uses service name
mysqlas DB hostExposed via port
5000Starts only after DB becomes healthy
🔹 Network
User-defined bridge network (
twotier)Enables DNS-based service discovery
1️⃣2️⃣ Start the Application
docker-compose up -d

Check:
docker-compose ps

Logs:
docker-compose logs -f
1️⃣3️⃣ Access the Application
Open browser:
http://<EC2-PUBLIC-IP>:5000
🎉 Your two-tier Flask + MySQL app is live on AWS.








