A production-ready, end-to-end DevOps pipeline for a Python/Flask task management application — containerised with Docker, orchestrated with Kubernetes, provisioned with Terraform, and served behind an Nginx reverse proxy with a PostgreSQL database.
- Overview
- Architecture
- Tech Stack
- Project Structure
- Prerequisites
- Getting Started
- Environment Variables
- Docker Details
- Kubernetes Details
- Terraform Details
- Contributing
- License
TaskHub is a full-stack task management web application designed to demonstrate a complete DevOps pipeline from local development to production deployment. The project showcases:
- Containerisation of a Python Flask application using Docker best practices (non-root user, slim base image, Gunicorn WSGI server)
- Multi-service local orchestration via Docker Compose (app + database + reverse proxy)
- Kubernetes manifests for scalable, cloud-native deployment
- Terraform configuration for repeatable infrastructure provisioning
- Nginx as a reverse proxy for the Flask application
┌─────────────┐
│ Client │
└──────┬──────┘
│ HTTP :80
┌──────▼──────┐
│ Nginx │ Reverse Proxy
└──────┬──────┘
│ :5000
┌──────▼──────┐
│ Flask / App │ Gunicorn WSGI
│ (Python) │
└──────┬──────┘
│
┌──────▼──────┐
│ PostgreSQL │ Persistent Storage
└─────────────┘
| Layer | Technology |
|---|---|
| Application | Python 3.11, Flask, Gunicorn |
| Database | PostgreSQL 15 |
| Reverse Proxy | Nginx (Alpine) |
| Containerisation | Docker, Docker Compose |
| Orchestration | Kubernetes |
| Infrastructure | Terraform (HCL) |
| Frontend | HTML, CSS |
taskhub-devops-pipeline/
├── app/ # Flask application source code
│ ├── app.py # Application entry point
│ ├── requirements.txt # Python dependencies
│ └── templates/ # HTML templates
├── kubernetes/ # Kubernetes manifests
│ ├── deployment.yaml # App Deployment
│ ├── service.yaml # Service definitions
│ └── ...
├── nginx/
│ └── nginx.conf # Nginx reverse proxy configuration
├── terraform/ # Infrastructure as Code
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Local development orchestration
└── .gitignore
Make sure the following tools are installed before getting started:
- Docker
>= 24.x - Docker Compose
>= 2.x - kubectl (for Kubernetes deployment)
- Terraform
>= 1.x(for infrastructure provisioning) - Python 3.11+ (for local development without Docker)
This is the fastest way to get the full stack running locally.
1. Clone the repository
git clone https://github.com/Hitendrasinhdata7/taskhub-devops-pipeline.git
cd taskhub-devops-pipeline2. Start all services
docker compose up --buildThis will start three services:
db— PostgreSQL database on the internal networkweb— Flask app served by Gunicorn on port5000nginx— Nginx reverse proxy exposed on port80
3. Open the app
http://localhost
4. Stop all services
docker compose downTo also remove the persistent database volume:
docker compose down -v1. Build and push the Docker image
docker build -t your-dockerhub-username/taskhub:latest .
docker push your-dockerhub-username/taskhub:latest2. Update the image reference in kubernetes/deployment.yaml to point to your image.
3. Apply the manifests
kubectl apply -f kubernetes/4. Verify the deployment
kubectl get pods
kubectl get services1. Navigate to the Terraform directory
cd terraform2. Initialise Terraform
terraform init3. Review the execution plan
terraform plan4. Apply the infrastructure
terraform apply5. Destroy infrastructure when done
terraform destroyThe application is configured via environment variables. These are set in docker-compose.yml for local development and should be passed as Kubernetes Secrets or ConfigMaps in production.
| Variable | Description | Default |
|---|---|---|
DB_HOST |
PostgreSQL host | db |
DB_NAME |
Database name | MyFirstAppDb |
DB_USER |
Database user | postgres |
DB_PASSWORD |
Database password | (see compose file) |
DB_PORT |
Database port | 5432 |
⚠️ Security Note: Never commit real credentials to version control. Use environment-specific secret management (e.g. Kubernetes Secrets, AWS Secrets Manager, or HashiCorp Vault) in production environments.
The Dockerfile follows production best practices:
- Base image:
python:3.11-slim— minimal footprint - Non-root user: The application runs as
appuserfor improved security - Gunicorn: Production-ready WSGI server instead of the Flask development server
- Port:
5000
# Key highlights
FROM python:3.11-slim
RUN adduser --disabled-password --gecos '' appuser
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]The kubernetes/ directory contains manifests for deploying TaskHub to any Kubernetes cluster (local via minikube or cloud-based via EKS/GKE/AKS):
- Deployment — defines replica count, container image, and environment config
- Service — exposes the app internally (ClusterIP) or externally (LoadBalancer/NodePort)
The terraform/ directory contains HCL configuration to provision the required cloud infrastructure (e.g. VPC, compute instances, managed database, container registry). Update variables.tf with your environment-specific values before running.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Commit your changes:
git commit -m 'Add some feature' - Push to the branch:
git push origin feature/your-feature-name - Open a Pull Request
This project is open source and available under the MIT License.
Built with ❤️ by Hitendrasinhdata7