zkt26/z2/README.md

382 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Task Manager — Kubernetes Deployment
A full-stack task management web application deployed on **Kubernetes**, extending the Docker Compose version (z1) with Kubernetes-native orchestration, scaling, and persistent storage.
## Table of Contents
- [Description](#description)
- [Prerequisites](#prerequisites)
- [Architecture](#architecture)
- [Kubernetes Objects](#kubernetes-objects)
- [Containers Used](#containers-used)
- [Networking](#networking)
- [Persistent Volumes](#persistent-volumes)
- [Container Configuration](#container-configuration)
- [Quick Start](#quick-start)
- [Usage Instructions](#usage-instructions)
- [Viewing the Application](#viewing-the-application)
- [Example Workflow](#example-workflow)
- [File Structure](#file-structure)
- [Sources](#sources)
- [Use of Artificial Intelligence](#use-of-artificial-intelligence)
---
## Description
**Task Manager** is a full-stack web application for creating, managing, and tracking tasks. Users can:
- **Create tasks** with a title and optional description
- **Mark tasks** as completed or reopen them
- **Delete tasks** they no longer need
- **Filter tasks** by status (All / Active / Completed)
- **View statistics** including total, active, and completed task counts
- **Manage the database** via Adminer web interface
The application consists of a dark-themed Nginx frontend, a Node.js/Express REST API backend, PostgreSQL for persistent task storage, and Redis for API response caching — all orchestrated by Kubernetes.
---
## Prerequisites
| Software | Minimum Version | Purpose |
|----------|----------------|---------|
| **Linux** | Any modern distribution | Host OS |
| **Docker** | 20.10+ | Build container images |
| **kubectl** | 1.25+ | Kubernetes CLI |
| **Minikube** or **kind** | Latest | Local Kubernetes cluster |
| **bash** | 4.0+ | Running management scripts |
### Verify installation:
```bash
docker --version
kubectl version --client
minikube version # or: kind version
```
### Start a local cluster (if not already running):
```bash
minikube start
# or
kind create cluster
```
---
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Namespace: taskmanager │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Kubernetes Cluster DNS │ │
│ │ │ │
│ │ NodePort :30080 NodePort :30081 │ │
│ │ │ │ │ │
│ │ ┌────▼──────────┐ ┌────────▼──────────┐ │ │
│ │ │ Service │ │ Service │ │ │
│ │ │ (frontend) │ │ (adminer) │ │ │
│ │ └────┬──────────┘ └────────┬──────────┘ │ │
│ │ │ │ │ │
│ │ ┌────▼──────────┐ ┌────────▼──────────┐ │ │
│ │ │ Deployment │ │ Deployment │ │ │
│ │ │ (Nginx ×1) │ │ (Adminer ×1) │ │ │
│ │ └────┬──────────┘ └────────┬──────────┘ │ │
│ │ │ /api/ proxy │ │ │
│ │ ┌────▼──────────┐ │ │ │
│ │ │ Service │ │ │ │
│ │ │ (api:3000) │ │ │ │
│ │ └────┬──────────┘ │ │ │
│ │ │ │ │ │
│ │ ┌────▼──────────┐ ┌────────▼──────────┐ │ │
│ │ │ Deployment │ │ StatefulSet │ │ │
│ │ │ (API ×2) │ │ (Postgres ×1) │ │ │
│ │ └───┬───────────┘ └────────┬──────────┘ │ │
│ │ │ │ PVC → PV │ │
│ │ ┌───▼──────────┐ │ /mnt/.../postgres │ │
│ │ │ StatefulSet │ │ │ │
│ │ │ (Redis ×1) │─────────────►│ │ │
│ │ └──────────────┘ │ │ │
│ │ PVC → PV │ │ │
│ │ /mnt/.../redis │ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## Kubernetes Objects
| Object | Name | File | Description |
|--------|------|------|-------------|
| **Namespace** | `taskmanager` | `namespace.yaml` | Isolates all objects from other cluster workloads |
| **Secret** | `postgres-secret` | `configmap-secret.yaml` | Stores base64-encoded DB username and password |
| **ConfigMap** | `postgres-init` | `configmap-secret.yaml` | Contains `init.sql` to create the tasks table on first run |
| **PersistentVolume** | `postgres-pv` | `statefulset.yaml` | 1 Gi host-path volume for PostgreSQL data |
| **PersistentVolumeClaim** | `postgres-pvc` | `statefulset.yaml` | Claims `postgres-pv` for the postgres StatefulSet |
| **PersistentVolume** | `redis-pv` | `statefulset.yaml` | 500 Mi host-path volume for Redis AOF data |
| **PersistentVolumeClaim** | `redis-pvc` | `statefulset.yaml` | Claims `redis-pv` for the redis StatefulSet |
| **StatefulSet** | `postgres` | `statefulset.yaml` | Manages the PostgreSQL 16 database pod with stable identity |
| **StatefulSet** | `redis` | `statefulset.yaml` | Manages the Redis 7 cache pod with stable identity |
| **Deployment** | `taskmanager-api` | `deployment.yaml` | Runs 2 replicas of the Node.js REST API |
| **Deployment** | `taskmanager-frontend` | `deployment.yaml` | Runs 1 replica of the Nginx frontend |
| **Deployment** | `taskmanager-adminer` | `deployment.yaml` | Runs 1 replica of Adminer (DB web UI) |
| **Service** | `postgres` | `service.yaml` | ClusterIP — internal access to PostgreSQL on port 5432 |
| **Service** | `redis` | `service.yaml` | ClusterIP — internal access to Redis on port 6379 |
| **Service** | `taskmanager-api` | `service.yaml` | ClusterIP — internal access to API on port 3000 |
| **Service** | `taskmanager-frontend` | `service.yaml` | NodePort — exposes UI at port 30080 |
| **Service** | `taskmanager-adminer` | `service.yaml` | NodePort — exposes Adminer at port 30081 |
---
## Containers Used
### 1. `taskmanager-frontend` (Custom — Nginx)
- **Image:** Built from `frontend/Dockerfile` using `nginx:alpine`
- **Role:** Serves the static HTML/CSS/JS UI and reverse-proxies `/api/` requests to `taskmanager-api:3000` using Kubernetes DNS resolution
- **Port:** 80 (internal), exposed at NodePort 30080
### 2. `taskmanager-api` (Custom — Node.js)
- **Image:** Built from `api/Dockerfile` using `node:20-alpine`
- **Role:** REST API providing full CRUD operations for tasks. Uses PostgreSQL for data and Redis for caching (30 s TTL). 2 replicas for availability
- **Port:** 3000 (ClusterIP)
### 3. `postgres` (Official — `postgres:16-alpine`)
- **Role:** Primary relational database. The `init.sql` ConfigMap is mounted into `/docker-entrypoint-initdb.d/` so the schema and sample data are created automatically the first time
- **Port:** 5432 (ClusterIP)
### 4. `redis` (Official — `redis:7-alpine`)
- **Role:** In-memory cache for task list API responses. Configured with append-only persistence (`--appendonly yes`) so the cache survives pod restarts
- **Port:** 6379 (ClusterIP)
### 5. `adminer` (Official — `adminer:latest`)
- **Role:** Web-based database management interface for browsing, querying, and managing the PostgreSQL database directly in a browser
- **Port:** 8080 (internal), exposed at NodePort 30081
---
## Networking
Kubernetes uses a **flat cluster network** — every pod can reach every other pod by its Service DNS name inside the same namespace.
| Service Name | Type | Port | Accessible From |
|-------------|------|------|----------------|
| `postgres` | ClusterIP | 5432 | API pods only (internal) |
| `redis` | ClusterIP | 6379 | API pods only (internal) |
| `taskmanager-api` | ClusterIP | 3000 | Frontend pods (Nginx proxy) |
| `taskmanager-frontend` | NodePort | 80 → 30080 | External (browser) |
| `taskmanager-adminer` | NodePort | 8080 → 30081 | External (browser) |
**DNS resolution example:** Inside the cluster, Nginx resolves `taskmanager-api` to the API Service IP automatically through Kubernetes DNS (`kube-dns`). The database and cache are not reachable from outside the cluster.
---
## Persistent Volumes
| Volume Name | Type | Capacity | Mount Path | Purpose |
|------------|------|----------|-----------|---------|
| `postgres-pv` | hostPath | 1 Gi | `/mnt/taskmanager/postgres` | PostgreSQL data directory |
| `redis-pv` | hostPath | 500 Mi | `/mnt/taskmanager/redis` | Redis append-only file |
**Data persistence:** Stopping the application by scaling to zero (`./stop-app.sh`) or restarting pods does **not** delete the host directories or PVs. Only `./remove-app.sh` deletes them.
---
## Container Configuration
All containers are configured using **environment variables**, **Secrets**, and **ConfigMaps**:
- **Secrets:** `postgres-secret` provides the database username and password to both the `postgres` StatefulSet and `taskmanager-api` Deployment, avoiding plain-text credentials in YAML files
- **ConfigMap:** `postgres-init` provides the `init.sql` script mounted as a file into the postgres container
- **Resource limits:** Every container has `requests` and `limits` defined to prevent resource starvation
- **Readiness/liveness probes:** All containers have health checks so Kubernetes only routes traffic to healthy pods and automatically restarts crashed pods
- **Restart policy:** Kubernetes restarts failed pods by default (managed by the Deployment/StatefulSet controllers)
- **StatefulSets** are used for PostgreSQL and Redis because they need a stable network identity and persistent storage. The API and frontend use Deployments because they are stateless and benefit from rolling updates
---
## Quick Start
```bash
# 1. Start a local Kubernetes cluster (if not already running)
minikube start
# 2. Prepare — build Docker images and create host directories
./prepare-app.sh
# 3. Deploy to Kubernetes
./start-app.sh
# 4. Open the app in your browser
# Task Manager: http://<NODE_IP>:30080
# Adminer: http://<NODE_IP>:30081
```
For Minikube, get the node IP with:
```bash
minikube ip
```
---
## Usage Instructions
### Preparing the application
```bash
./prepare-app.sh
```
Builds the custom Docker images (`taskmanager-api:latest`, `taskmanager-frontend:latest`), creates the host-path directories used by the PersistentVolumes, and **automatically loads the images into Minikube** if it detects a running Minikube cluster (preventing `ImagePullBackOff` errors).
### Starting the application
```bash
./start-app.sh
```
Applies all Kubernetes manifests in the correct dependency order and waits for StatefulSets and Deployments to be ready. Prints the access URLs at the end.
### Stopping and removing the application
```bash
./stop-app.sh
```
Deletes **all** Kubernetes objects (Deployments, StatefulSets, Services, PVCs, Secrets, ConfigMap, Namespace) and the PersistentVolumes and host directories.
⚠️ **All task data will be lost.** Run `./prepare-app.sh` then `./start-app.sh` to start fresh.
### Pausing without data loss
```bash
# Scale all workloads to 0 — objects and PVs remain, data is preserved
kubectl scale deployment --all --replicas=0 -n taskmanager
kubectl scale statefulset --all --replicas=0 -n taskmanager
# Resume
./start-app.sh
```
---
## Viewing the Application
### Task Manager (Main UI)
- **URL:** `http://<NODE_IP>:30080`
- For Minikube: `http://$(minikube ip):30080`
- Features: Create, complete, delete, and filter tasks
### Adminer (Database Management)
- **URL:** `http://<NODE_IP>:30081`
- **Login credentials:**
- System: `PostgreSQL`
- Server: `postgres`
- Username: `taskuser`
- Password: `taskpass`
- Database: `taskmanager`
---
## Example Workflow
```bash
# Start a Minikube cluster
$ minikube start
# Prepare images and host directories
$ ./prepare-app.sh
=============================================
Preparing Task Manager for Kubernetes...
=============================================
[1/2] Building Docker images...
✓ taskmanager-api:latest built
✓ taskmanager-frontend:latest built
[2/2] Creating host directories for PersistentVolumes...
✓ /mnt/taskmanager/postgres created
✓ /mnt/taskmanager/redis created
=============================================
✓ Preparation complete!
Run ./start-app.sh to deploy to Kubernetes
=============================================
# Deploy the application
$ ./start-app.sh
=============================================
Starting Task Manager on Kubernetes...
=============================================
[1/6] Creating Namespace...
[2/6] Applying Secrets and ConfigMaps...
[3/6] Applying PersistentVolumes, PVCs and StatefulSets...
[4/6] Waiting for postgres StatefulSet to be Ready...
Waiting for redis StatefulSet to be Ready...
[5/6] Applying Deployments...
[6/6] Applying Services...
Waiting for API deployment to be ready...
=============================================
✓ Task Manager is running!
🌐 Task Manager: http://192.168.49.2:30080
🗄️ Adminer (DB): http://192.168.49.2:30081
=============================================
# Stop (data preserved)
$ ./stop-app.sh
✓ Application stopped. Data is preserved in PersistentVolumes.
# Start again — all tasks still there
$ ./start-app.sh
# Remove everything
$ ./remove-app.sh
✓ Application completely removed.
```
---
## File Structure
```
z2/
├── namespace.yaml # Namespace: taskmanager
├── configmap-secret.yaml # Secret (DB credentials) + ConfigMap (init.sql)
├── statefulset.yaml # PV, PVC, StatefulSet for postgres and redis
├── deployment.yaml # Deployments for API, frontend, adminer
├── service.yaml # Services (ClusterIP + NodePort)
├── prepare-app.sh # Build images, create host directories
├── start-app.sh # Deploy all Kubernetes objects
├── stop-app.sh # Scale to zero (pause)
├── remove-app.sh # Delete everything
├── README.md # This documentation
├── api/
│ ├── Dockerfile # Node.js 20 Alpine image
│ ├── package.json # Node dependencies
│ ├── server.js # Express REST API
│ └── db.js # PostgreSQL connection pool
├── frontend/
│ ├── Dockerfile # Nginx Alpine image
│ ├── nginx.conf # Nginx config (proxies /api/ → taskmanager-api)
│ └── public/
│ ├── index.html # Task Manager SPA
│ ├── style.css # Dark theme CSS
│ └── app.js # Frontend JavaScript
└── db/
└── init.sql # Database schema + sample data
```
---
## Sources
1. **Kubernetes Documentation** — [https://kubernetes.io/docs/](https://kubernetes.io/docs/)
2. **kubectl Reference** — [https://kubernetes.io/docs/reference/kubectl/](https://kubernetes.io/docs/reference/kubectl/)
3. **Kubernetes: StatefulSets** — [https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
4. **Kubernetes: Persistent Volumes** — [https://kubernetes.io/docs/concepts/storage/persistent-volumes/](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
5. **Kubernetes: Secrets** — [https://kubernetes.io/docs/concepts/configuration/secret/](https://kubernetes.io/docs/concepts/configuration/secret/)
6. **Minikube Documentation** — [https://minikube.sigs.k8s.io/docs/](https://minikube.sigs.k8s.io/docs/)
7. **PostgreSQL Docker Image** — [https://hub.docker.com/_/postgres](https://hub.docker.com/_/postgres)
8. **Redis Docker Image** — [https://hub.docker.com/_/redis](https://hub.docker.com/_/redis)
9. **Adminer Docker Image** — [https://hub.docker.com/_/adminer](https://hub.docker.com/_/adminer)
10. **Node.js Docker Image** — [https://hub.docker.com/_/node](https://hub.docker.com/_/node)
11. **Nginx Docker Image** — [https://hub.docker.com/_/nginx](https://hub.docker.com/_/nginx)
12. **Express.js Documentation** — [https://expressjs.com/](https://expressjs.com/)
---
## Use of Artificial Intelligence
Artificial intelligence tools such as ChatGPT and Claude were used as a support tool during development for understanding Kubernetes concepts, writing YAML manifests, and debugging configuration issues. All implementation, testing, and integration were performed independently.