Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Automated Web Application Deployment using Docker, Jenkins & AWS

A small Python Flask web app that deploys itself. When I push code to GitHub, a Jenkins pipeline on an AWS EC2 server runs the tests, builds a Docker image and replaces the running container with the new version. Nginx sits in front of the app as a reverse proxy.

I built this project to learn how a basic CI/CD pipeline works from start to end.

Architecture

Architecture diagram

Flow in short:

  1. I push code to the main branch on GitHub.
  2. GitHub sends a webhook to Jenkins running on EC2.
  3. Jenkins pulls the code and runs the stages in the Jenkinsfile: Checkout, Test, Build Image, Deploy, Health Check.
  4. The new Docker container runs the app with Gunicorn on port 5000 (only reachable from inside the server).
  5. Nginx listens on port 80 and forwards public traffic to the container.

If any test fails, the pipeline stops and the old version keeps running.

Tech stack

Tool What it does in this project
Python + Flask The web application
pytest Automated tests
Gunicorn Production web server inside the container
Git + GitHub Version control and source of truth for the code
Docker Packages the app and its dependencies into an image
Jenkins Runs the CI/CD pipeline
AWS EC2 (Ubuntu 24.04) The cloud server where everything runs
Nginx Reverse proxy on port 80
Linux / Bash Server setup and pipeline shell steps

Project structure

devops-flask-app/
├── app.py                 # Flask application
├── templates/
│   └── index.html         # Home page HTML
├── test_app.py            # pytest tests
├── requirements.txt       # Pinned Python packages
├── gunicorn.conf.py       # Gunicorn settings (port, workers)
├── Dockerfile             # How to build the Docker image
├── .dockerignore          # Files kept out of the image
├── Jenkinsfile            # CI/CD pipeline definition
├── nginx/
│   └── flask-app.conf     # Nginx reverse proxy config
├── scripts/
│   └── ec2-setup.sh       # Installs Docker, Jenkins, Nginx on EC2
└── docs/
    ├── architecture.png
    ├── SETUP_GUIDE.md     # Step by step deployment guide
    ├── CHALLENGES.md      # Problems I faced and how I fixed them
    ├── RESUME.md          # Resume description of the project
    └── Project_Report.pdf # Full project report in simple English

Run it locally

python -m venv venv
venv\Scripts\activate        # on Linux or Mac: source venv/bin/activate
pip install -r requirements.txt
pytest
python app.py

Open http://localhost:5000 and http://localhost:5000/health

Run it with Docker

docker build -t flask-app .
docker run -d -p 5000:5000 flask-app

App endpoints

URL Response
/ Home page showing the current build number
/health {"status": "ok"} used by the pipeline health check

Pipeline stages

Stage What happens
Checkout Jenkins pulls the latest code from GitHub
Test Creates a virtual environment and runs pytest
Build Docker Image Builds flask-app:<build number> and flask-app:latest
Deploy Stops the old container and starts the new one
Health Check Calls /health until the app answers, fails the build if it never does

The Jenkins build number is passed to the container as APP_VERSION, so the home page shows which build is live.

Keeping it DRY (Don't Repeat Yourself)

I tried to define every value in one place only, so a change never has to be made in two files:

Value or code Defined once in Used by
App port PORT env variable (Dockerfile) and APP_PORT (Jenkinsfile) Flask, Gunicorn, docker run, health check
Image and container names environment block in the Jenkinsfile Build, Deploy and Health Check stages
Nginx config nginx/flask-app.conf The setup script downloads it from this repo instead of keeping a second copy
Server settings (repo, swap size, log file) Variables at the top of scripts/ec2-setup.sh The whole script
Home page HTML templates/index.html Flask render_template
Test setup A pytest fixture plus parametrize All tests share one client, status code checks share one test

Phases

The project was built in 7 phases. Each phase is one commit and has a git tag (phase-1 to phase-7), so you can see how it grew:

Phase What was added
1 Flask app and tests
2 Docker (Dockerfile, Gunicorn)
3 EC2 server setup script
4 Nginx reverse proxy
5 Jenkins pipeline (Jenkinsfile)
6 GitHub webhook and setup guide
7 Documentation, architecture diagram and project report

Deployment

Full steps are in docs/SETUP_GUIDE.md.

Challenges

See docs/CHALLENGES.md.

What I would add next

  • HTTPS with a domain name and Let's Encrypt
  • Push images to Docker Hub or Amazon ECR instead of building on the same server
  • Run Jenkins on a separate server from the app
  • Slack or email notifications when a build fails
  • Infrastructure as code with Terraform

Author

Radhika Agarwal, B.Tech Artificial Intelligence and Data Science
GitHub: radhikaa06

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages