Go to file
Brazing Technology 387b462673 update qubernetees
2026-04-29 14:52:01 +05:30
.claude update qubernetees 2026-04-29 14:52:01 +05:30
backend feat(backend): add Dockerfile for taskapp-api image 2026-04-29 11:21:56 +05:30
docs/superpowers update qubernetees 2026-04-29 14:52:01 +05:30
frontend update qubernetees 2026-04-29 14:52:01 +05:30
.gitignore chore: initial repo, copy source from assignment 1 2026-04-29 11:20:19 +05:30
deployment.yaml feat(k8s): api and web Deployments with probes and resources 2026-04-29 11:29:26 +05:30
namespace.yaml feat(k8s): namespace, secret, configmap manifests 2026-04-29 11:26:24 +05:30
nginx.conf feat(frontend): add Dockerfile and nginx.conf for ConfigMap 2026-04-29 11:22:33 +05:30
prepare-app.sh feat(scripts): prepare-app.sh — build images, create PV 2026-04-29 11:29:47 +05:30
README.md docs: README covering app, K8s objects, networks, volumes, lifecycle 2026-04-29 11:31:18 +05:30
service.yaml feat(k8s): web NodePort, api ClusterIP, db headless services 2026-04-29 11:28:25 +05:30
start-app.sh feat(scripts): start-app.sh — apply all manifests, open browser 2026-04-29 11:30:04 +05:30
statefulset.yaml feat(k8s): PV, PVC, StatefulSet for postgres 2026-04-29 11:27:18 +05:30
stop-app.sh feat(scripts): stop-app.sh — full teardown 2026-04-29 11:30:18 +05:30

Task Manager on Kubernetes

A web-based task manager (Nginx + Flask + PostgreSQL) deployed to a Kubernetes cluster (minikube). Migrated from the Docker Compose version in the first assignment.

What the application does

A simple CRUD task manager. Users can:

  • Add a new task by typing a title and pressing Enter.
  • Mark a task as completed by toggling its checkbox.
  • Delete a task by clicking the X button.
  • See all tasks sorted by creation date.

The frontend is a static page served by Nginx. The backend is a Flask REST API. Tasks are stored in PostgreSQL and survive pod restarts thanks to a hostPath PersistentVolume.

Prerequisites

  • minikube (any recent version, tested with 1.32+)
  • kubectl (any version compatible with the minikube cluster)
  • Docker CLI (used by prepare-app.sh to build images directly into minikube's docker daemon)
  • bash (Linux/macOS native; Git Bash on Windows)

Containers used

Container Image Description
web taskapp-web:v1 (built locally from nginx:alpine) Serves static HTML/CSS/JS and reverse-proxies /api/* to the api Service. nginx.conf is mounted from a ConfigMap.
api taskapp-api:v1 (built locally from python:3.12-slim) Flask REST API on Gunicorn (2 workers). Exposes GET/POST /api/tasks, PUT /api/tasks/:id, DELETE /api/tasks/:id, GET /api/health.
db postgres:15 (Docker Hub) Stores tasks table. Data lives at /var/lib/postgresql/data on a PersistentVolume backed by hostPath.

Kubernetes objects

Object Name Description
Namespace taskapp Isolates every other resource.
Secret db-credentials Holds POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD. Consumed by both Postgres and Flask via envFrom.
ConfigMap nginx-config Holds nginx.conf. Mounted into the web container at /etc/nginx/nginx.conf via subPath.
PersistentVolume db-pv 1 Gi, hostPath: /mnt/data/taskapp-db on the minikube node. ReclaimPolicy Retain. StorageClass manual.
PersistentVolumeClaim db-pvc 1 Gi, ReadWriteOnce, binds to db-pv via label selector. Mounted by the StatefulSet.
StatefulSet db 1 replica, postgres:15. Uses the PVC. Has liveness and readiness probes (pg_isready).
Deployment api 2 replicas, custom Flask image. Probes hit GET /api/health (which checks DB reachability).
Deployment web 2 replicas, custom Nginx image. Probes hit GET /.
Service web NodePort 30080 → 80. The only externally reachable Service.
Service api ClusterIP, port 5000. Internal only.
Service db Headless (clusterIP: None), port 5432. Internal only. Pairs with the StatefulSet for stable DNS.

Virtual networks

The cluster's CNI plugin handles all pod-to-pod traffic. Service discovery is via Kubernetes DNS (kube-dns / coredns):

  • Inside the namespace, every Service is reachable by short name: web, api, db.
  • The web Service is the only one exposed outside the cluster (NodePort 30080).
  • The db Service is headless — it returns the pod IPs directly instead of load-balancing. This is the canonical pattern for StatefulSets and gives db-0 a stable DNS identity (db-0.db.taskapp.svc.cluster.local).

Named volumes

Volume Mount Backed by Reclaim policy
db-pv (PVC db-pvc) /var/lib/postgresql/data (in db-0) hostPath /mnt/data/taskapp-db on the minikube node Retain

Retain means deleting the PVC does not automatically wipe the underlying directory — the data survives even a full stop-app.sh and is reattached on the next prepare-app.sh + start-app.sh. To wipe it manually:

minikube ssh -- sudo rm -rf /mnt/data/taskapp-db

Container configuration performed

  • web — built from nginx:alpine plus the static frontend files. The nginx.conf is supplied at runtime via the nginx-config ConfigMap, mounted with subPath: nginx.conf so only that single file is overlaid (not the whole config directory). This means the proxy rule (proxy_pass http://api_backend;) and large_client_header_buffers setting can be edited by changing the ConfigMap and reloading, without rebuilding the image.
  • api — built from python:3.12-slim, installs libpq-dev and gcc for the psycopg2 build, then pip install of requirements.txt (Flask + Gunicorn + psycopg2). Runs Gunicorn with 2 workers on port 5000. Reads DB credentials from env vars sourced from the db-credentials Secret.
  • db — official postgres:15 image, unmodified. Env (DB name, user, password) sourced from the same Secret. PGDATA is set to /var/lib/postgresql/data/pgdata (a subdir) because Postgres refuses to initialize a non-empty data directory and hostPath dirs occasionally have stray entries.

Resource requests/limits are set on every container so the cluster scheduler can place pods predictably; values are conservative and tested against a 4 GiB minikube VM.

Usage

Prepare the application

Builds images directly into minikube's docker daemon, creates the hostPath directory on the node, and applies Namespace + Secret + ConfigMap + PV + PVC + StatefulSet.

./prepare-app.sh

Start the application

Applies the Deployments and Services. (Re-applies prepare-stage resources idempotently, so it's safe to run on its own too.)

./start-app.sh

The script then opens your default browser at http://<minikube-ip>:30080.

Pause / stop the application

stop-app.sh removes every Kubernetes object (Deployments, Services, StatefulSet, PVC, PV, Namespace, Secret, ConfigMap):

./stop-app.sh

The hostPath data on the minikube node is retained (PV ReclaimPolicy = Retain). To resume from where you left off, run ./prepare-app.sh && ./start-app.sh again.

Delete everything (including data)

./stop-app.sh
minikube ssh -- sudo rm -rf /mnt/data/taskapp-db

Viewing the application in a web browser

After ./start-app.sh finishes, run:

minikube service web -n taskapp

This opens the browser at the right URL automatically. Alternatively, navigate manually:

echo "http://$(minikube ip):30080"

You'll see the Task Manager interface where you can add, complete, and delete tasks.

API endpoints

Method Endpoint Description
GET /api/health Health check (200 if DB reachable, 503 otherwise). Used by readiness probe.
GET /api/tasks List all tasks.
POST /api/tasks Create a task. Body: {"title": "..."}.
PUT /api/tasks/:id Toggle completion.
DELETE /api/tasks/:id Delete a task.

Project structure

qubernetees/
├── README.md              # this file
├── prepare-app.sh         # build images, create PV, apply prepare-stage manifests
├── start-app.sh           # apply Deployments + Services, open browser
├── stop-app.sh            # full teardown
├── namespace.yaml         # Namespace + Secret + ConfigMap
├── statefulset.yaml       # PV + PVC + StatefulSet
├── deployment.yaml        # api + web Deployments
├── service.yaml           # api + web + db Services
├── nginx.conf             # source of the ConfigMap (kept for readability)
├── backend/               # Flask REST API
│   ├── Dockerfile
│   ├── requirements.txt
│   └── app.py             # + /api/health endpoint
└── frontend/              # static HTML/CSS/JS
    ├── Dockerfile
    ├── index.html
    ├── style.css
    └── app.js

Sources

Use of Artificial Intelligence

This Kubernetes deployment was designed and implemented with the assistance of Claude (Anthropic), an AI assistant. Claude was used for:

  • Designing the K8s object topology (Namespace, Deployments, StatefulSet, PV, PVC, Services).
  • Authoring the manifest files, lifecycle scripts, and this documentation.
  • Reviewing the design against the assignment requirements.

AI agent used: Claude Opus 4.7 (Anthropic) via Claude Code CLI.

The application logic itself (Flask backend, frontend) was carried over from the first assignment.