A comprehensive demonstration of the DevOps cycle: From basic Scripting, Containerization, IaC, to Kubernetes Orchestration.
This project is more than just a simple Python application. It serves as a living laboratory where I implemented "Automation First" and "Infrastructure as Code" principles from the ground up.
The main goal was to build a system that is:
- Portable: Runs anywhere seamlessly (Docker).
- Reliable: Code is validated automatically before merging (CI).
- Reproducible: Infrastructure is provisioned via code, not manual clicks (Terraform/Ansible).
- Unbreakable: The application is self-healing (Kubernetes).
In this project, I acted as a DevOps Engineer building infrastructure from scratch. Here are the development phases:
Established the foundation for server automation.
- Developed
setup_server.shscripts for simulating server provisioning. - Implemented Logic Control to prevent redundant installations (Basic Idempotency).
- Managed security via Environment Variables (
.env) to avoid hardcoding database credentials. - Implemented an automated logging system storing outputs in
logs/.
Solved the "It works on my machine" dilemma.
- Packaged the Python Flask application and its dependencies using Dockerfile (Multi-stage build concept).
- Orchestrated the connection between the App and the Database (Redis) using Docker Compose.
- Ensured the application runs in an isolated environment with internal Docker networking.
Deployed the "Automated Gatekeeper" to the repository.
- Configured the pipeline in
.github/workflows/ci.yml. - Linting: Automated checks for Python code quality (Flake8).
- Build Test: Automated validation to ensure the Docker Image builds successfully on every
git push.
Moved away from manual server provisioning.
- Used Terraform to provision Docker infrastructure declaratively.
- Learned and applied Immutable Infrastructure concepts: changing configuration triggers a resource replacement rather than an in-place edit.
- Managed infrastructure state tracking via
terraform.tfstate.
Automated internal server configuration.
- Utilized Ansible Playbooks to setup the application environment inside target servers.
- Leveraged the
docker_containerconnection plugin for agentless management (no SSH required for local docker). - Injected dynamic configuration files containing server timestamps using Jinja2 templates.
The final stage: High Availability & Self-Healing.
- Migrated from Docker Compose to Kubernetes (K8s).
- Created Deployments for both the Python App and Redis.
- Implemented Service Discovery allowing the app to resolve the Redis database via internal Cluster DNS.
- Self-Healing Test: Verified that Kubernetes automatically resurrects Pods if they are forcibly terminated.
| Category | Technology | Usage in Project |
|---|---|---|
| Language | Python (Flask) | REST API application with a Redis Visit Counter |
| Scripting | Bash | Local environment automation & setup |
| Container | Docker | Application packaging |
| Orchestrator | Kubernetes (Minikube) | Cluster management, scaling, and self-healing |
| IaC | Terraform | Container infrastructure provisioning |
| Config Mgmt | Ansible | Server configuration & file management |
| CI/CD | GitHub Actions | Automated Testing & Build Validation |
You can run this project in two modes:
Use this for local development.
# Clone the repo
git clone https://github.com/AdnSmile/devops-unbreakable-app.git
cd devops-unbreakable-app
# Run services
docker-compose up --buildAccess the app at: http://localhost:8000
Use this to demonstrate self-healing capabilities. Prerequisite: Minikube & Kubectl installed.
# 1. Start the Cluster
minikube start
# 2. Point Docker Client to Minikube
eval $(minikube docker-env)
# 3. Build Image inside the Cluster
docker build -t my-python-app:v1 .
# 4. Deploy Redis & App
kubectl apply -f k8s/redis.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
# 5. Access the Application
minikube service unbreakable-app-serviceOne of the key features of Kubernetes is resilience. Try killing a Pod while the app is running:
# 1. List running pods
kubectl get pods
# 2. Kill (Delete) one of the app pods
kubectl delete pod [POD_NAME]
# 3. Watch the magic happen
kubectl get pods -wResult: Kubernetes will detect the dead pod and immediately spin up a new replacement. The user experiences zero downtime.
Created as part of my "Zero to Hero" DevOps learning journey.