π Description
A hands-on DevOps showcase: containerization, Kubernetes with Helm, CI/CD using GitHub Actions, and observability with Prometheus, all running locally.
In this article, I walk through a DevOps project I recently completed, a fully containerized full-stack web application deployed on a local Kubernetes cluster. This project was designed not just to build a functional app, but to demonstrate my DevOps skills end-to-end: containerization, orchestration, CI/CD, and observability.
π οΈ Project Overview
π§ Project Goal:
The goal was to create a simple yet realistic web app and apply modern DevOps practices around it. Here's what the application does:
- A React frontend collects user information.
- The data is sent to a Flask backend, which checks if the user already exists.
- If not, it adds the user to a PostgreSQL database.
- Redis is used to cache the user data for faster reads.
- Nginx acts as a reverse proxy to route traffic efficiently.
Simple in logic, but powerful as a DevOps exercise.
π¦ Containerization with Docker
π³ Consistent builds everywhere.
Each component of the stack React front-end, Flask back-end, PostgreSQL, Redis, and Nginx was packaged into its own Docker container. I created Dockerfiles for the front-end, back-end,PostgrSQL and Nginx while the using redis official images
I pushed all my custom images to Docker Hub, making them easy to deploy anywhere.
βΈοΈ Kubernetes Orchestration with Helm
π§ Template-driven deployments.
I chose Minikube as my local Kubernetes distribution because itβs lightweight and easy to set up.
To manage deployments efficiently, I used Helm charts. Helm made it easier to define and template Kubernetes manifests for each component. It allowed me to quickly spin up or update the application by adjusting just a few values.
Key Kubernetes resources used:
- Deployments for the front-end, back-end, and Nginx
- StatefulSet for PostgreSQL
- Persistent Volumes for database storage
- ConfigMaps and Secrets for environment variables
- Ingress configured with Nginx for routing
π Reverse Proxy with NGINX
π£οΈ Traffic routing made simple.
NGINX was configured as a reverse proxy to route external traffic efficiently to the back-end services and enforce separation of concerns.
β‘ Caching with Redis
π Faster response times.
Redis was integrated as an in-memory store to cache user data, helping reduce database load and improve response times.
π PostgreSQL for Persistent Storage
ποΈ Reliable relational storage.
PostgreSQL was used as the main relational database, storing all user information reliably with persistent volumes on Kubernetes.
π Observability with Prometheus, Grafana & Alertmanager
π Visualizing performance.
Monitoring is essential for any production-grade system. I deployed the Prometheus stack, including Grafana and Alertmanager inside the cluster.
- Prometheus scraped metrics from pods and the Kubernetes API.
- Grafana provided dashboards to visualize system performance (CPU, memory, request latency).
- I configured Alertmanager to send alerts to a Slack channel when thresholds were breached (e.g., high memory usage or pod crashes).
π CI/CD with GitHub Actions and Self-Hosted Runner
π€ Automated delivery pipeline.
To complete the DevOps lifecycle, I set up a full CI/CD pipeline using GitHub Actions.
CI/CD Workflow:
- Lint and test the code (for front-end/back-end).
- Build Docker images.
- Push to Docker Hub.
- Trigger a deployment to my MicroK8s cluster.
Since the cluster was running locally, I used a self-hosted GitHub Actions runner installed on my laptop. This allowed the pipeline to build and deploy directly to my local Kubernetes environment no cloud required.
β οΈ Challenges & Lessons Learned
π§© Solving real-world problems.
- Ingress and Service Networking: Getting Nginx ingress to work with service routing locally took some tweaking.
- Secrets Management: Managing database credentials and API keys securely in Kubernetes taught me the importance of Secrets and RBAC.
- Resource Limits: Without setting proper resource requests/limits, some pods would get evicted under memory pressure.
- CI/CD Integration: Setting up a self-hosted GitHub runner took some trial and error but was a great learning experience.
β Final Thoughts
This project helped me strengthen my understanding of the entire DevOps lifecycle:
- From writing Dockerfiles to managing deployments with Helm
- From local Kubernetes orchestration to building CI/CD pipelines
- From setting up observability tools to configuring real-time alerts
It was a rewarding experience that sharpened my technical skills and gave me a deeper appreciation for system reliability and automation.
π Want to See the Code?
Feel free to check out the project repository on GitHub:
π Github Repo
If you have any questions or feedback, Iβd love to hear from you in the comments!
Top comments (2)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.