From 18a369f5ad90a40cb8d881dd71480422e366d95e Mon Sep 17 00:00:00 2001 From: Nihal Ahmed Date: Thu, 14 May 2026 07:35:50 +0000 Subject: [PATCH] commit --- Dockerfile | 10 +++ README.md | 189 +++++++++++++++++++++++++++++++++++++++++++++++ configmap.yaml | Bin 0 -> 1024 bytes crud.py | 12 +++ database.py | 10 +++ deployment.yaml | 44 +++++++++++ index.html | 145 ++++++++++++++++++++++++++++++++++++ init.sql | 4 + main.py | 36 +++++++++ models.py | 8 ++ namespace.yaml | 4 + nginx.conf | 8 ++ package.json | 4 + prepare-app.sh | 3 + requirements.txt | 6 ++ schemas.py | 11 +++ secret.yaml | Bin 0 -> 1024 bytes service.yaml | 25 +++++++ start-app.sh | 3 + statefulset.yaml | 51 +++++++++++++ stop-app.sh | 3 + vite.config.js | 1 + 22 files changed, 577 insertions(+) create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 configmap.yaml create mode 100644 crud.py create mode 100644 database.py create mode 100644 deployment.yaml create mode 100644 index.html create mode 100644 init.sql create mode 100644 main.py create mode 100644 models.py create mode 100644 namespace.yaml create mode 100644 nginx.conf create mode 100644 package.json create mode 100644 prepare-app.sh create mode 100644 requirements.txt create mode 100644 schemas.py create mode 100644 secret.yaml create mode 100644 service.yaml create mode 100644 start-app.sh create mode 100644 statefulset.yaml create mode 100644 stop-app.sh create mode 100644 vite.config.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..393dff9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.10 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install -r requirements.txt + +COPY . . + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5a269d --- /dev/null +++ b/README.md @@ -0,0 +1,189 @@ +# Notes Application on Kubernetes + +## πŸ“Œ Description + +This project is a simple full-stack **Notes Application** deployed on Kubernetes. +It allows users to create and view notes through a web interface. The application demonstrates a complete **3-tier architecture**: + +* Frontend (User Interface) +* Backend (API Server) +* Database (PostgreSQL) + +The application is containerized using Docker and deployed using Kubernetes. + +--- + +## 🧱 Application Architecture + +The system consists of three main components: + +### 1. Frontend + +* Built using HTML and JavaScript +* Served via Nginx +* Provides UI for adding and viewing notes +* Communicates with backend using HTTP requests + +### 2. Backend + +* Built using FastAPI (Python) +* Provides REST API endpoints: + + * `GET /notes` + * `POST /notes` +* Handles business logic and database interaction + +### 3. Database + +* PostgreSQL database +* Stores notes persistently +* Managed using Kubernetes StatefulSet + +--- + +## πŸ“¦ Containers Used + +| Container | Description | +| --------- | --------------------------------------------- | +| frontend | Nginx container serving static frontend files | +| backend | FastAPI application handling API requests | +| postgres | PostgreSQL database for storing notes | + +--- + +## ☸️ Kubernetes Objects + +| Object | Description | +| --------------------------- | -------------------------------------------- | +| Namespace | `notes-app` – isolates application resources | +| Deployment | Manages frontend and backend pods | +| StatefulSet | Manages PostgreSQL with persistent storage | +| Service | Enables communication between components | +| PersistentVolume (PV) | Provides storage for database | +| PersistentVolumeClaim (PVC) | Requests storage for PostgreSQL | + +--- + +## 🌐 Networking + +* Communication is handled using Kubernetes **Services** +* Backend is accessible via: + + ``` + http://backend-service + ``` +* PostgreSQL is accessible via: + + ``` + postgres + ``` +* Frontend is exposed externally using **NodePort** + +--- + +## πŸ’Ύ Storage + +* PostgreSQL uses persistent storage via: + + * PersistentVolume (PV) + * PersistentVolumeClaim (PVC) +* Ensures data is retained even if pods restart + +--- + +## βš™οΈ Container Configuration + +### Backend Configuration + +```text +DATABASE_URL=postgresql://user:password@postgres:5432/notesdb +``` + +### Frontend Configuration + +```text +const API_URL = "http://backend-service"; +``` + +--- + +## πŸš€ How to Run the Application + +### 1. Prepare the Application + +```bash +./scripts/prepare-app.sh +``` + +Builds Docker images and prepares environment. + +--- + +### 2. Start the Application + +```bash +./scripts/start-app.sh +``` + +Deploys all Kubernetes resources. + +--- + +### 3. Access the Application + +#### Option 1: NodePort + +``` +http://localhost:30007 +``` + +#### Option 2: Port Forward (recommended for Docker Desktop) + +```bash +kubectl port-forward service/frontend-service 8080:80 -n notes-app +``` + +Then open: + +``` +http://localhost:8080 +``` + +--- + +### 4. Stop the Application + +```bash +./scripts/stop-app.sh +``` + +Deletes all Kubernetes resources. + +--- + +## πŸ§ͺ Functionality + +* Users can add notes via UI +* Notes are stored in PostgreSQL +* Data persists across restarts + +--- + +## πŸ“ Notes + +* Docker images are hosted on Docker Hub +* Kubernetes cluster used: Docker Desktop Kubernetes +* Application demonstrates real-world container orchestration + +--- + +## πŸ“š References + +* OpenAI. (2026). ChatGPT (GPT-5.5). https://chat.openai.com + Used for guidance on Kubernetes deployment, debugging, and structuring the application. + +--- + +## πŸ‘¨β€πŸ’» Author + +Nihal Ahmed diff --git a/configmap.yaml b/configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..06d7405020018ddf3cacee90fd4af10487da3d20 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/crud.py b/crud.py new file mode 100644 index 0000000..5a0bd84 --- /dev/null +++ b/crud.py @@ -0,0 +1,12 @@ +from sqlalchemy.orm import Session +import models, schemas + +def create_note(db: Session, note: schemas.NoteCreate): + db_note = models.Note(content=note.content) + db.add(db_note) + db.commit() + db.refresh(db_note) + return db_note + +def get_notes(db: Session): + return db.query(models.Note).all() \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..85a13b6 --- /dev/null +++ b/database.py @@ -0,0 +1,10 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker, declarative_base +import os + +DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://user:password@postgres:5432/notesdb") + +engine = create_engine(DATABASE_URL) +SessionLocal = sessionmaker(bind=engine) + +Base = declarative_base() \ No newline at end of file diff --git a/deployment.yaml b/deployment.yaml new file mode 100644 index 0000000..72e058f --- /dev/null +++ b/deployment.yaml @@ -0,0 +1,44 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend + namespace: notes-app +spec: + replicas: 1 + selector: + matchLabels: + app: backend + template: + metadata: + labels: + app: backend + spec: + containers: + - name: backend + image: nihal0314/backend:latest # βœ… FIXED + env: + - name: DATABASE_URL + vvalue: postgresql://user:password@postgres:5432/notesdb + ports: + - containerPort: 5000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + namespace: notes-app +spec: + replicas: 1 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: frontend + image: nihal0314/frontend:latest # βœ… FIXED + ports: + - containerPort: 80 \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..fcd3e3b --- /dev/null +++ b/index.html @@ -0,0 +1,145 @@ + + + + + + Notes App + + + + + + +
+

Notes App

+ +
+ + +
+ +
+ + +
+ + + + + + \ No newline at end of file diff --git a/init.sql b/init.sql new file mode 100644 index 0000000..a6ec2c5 --- /dev/null +++ b/init.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS notes ( + id SERIAL PRIMARY KEY, + content TEXT +); \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..1e9703b --- /dev/null +++ b/main.py @@ -0,0 +1,36 @@ +from fastapi import FastAPI, Depends +from sqlalchemy.orm import Session +import models +from database import engine, SessionLocal +import crud, schemas +from fastapi.middleware.cors import CORSMiddleware +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@app.get("/") +def root(): + return {"message": "API is running"} + +@app.post("/notes") +def create(note: schemas.NoteCreate, db: Session = Depends(get_db)): + return crud.create_note(db, note) + +@app.get("/notes") +def read(db: Session = Depends(get_db)): + return crud.get_notes(db) \ No newline at end of file diff --git a/models.py b/models.py new file mode 100644 index 0000000..cb87f78 --- /dev/null +++ b/models.py @@ -0,0 +1,8 @@ +from sqlalchemy import Column, Integer, String +from database import Base + +class Note(Base): + __tablename__ = "notes" + + id = Column(Integer, primary_key=True, index=True) + content = Column(String, index=True) \ No newline at end of file diff --git a/namespace.yaml b/namespace.yaml new file mode 100644 index 0000000..b75e884 --- /dev/null +++ b/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: notes-app \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..6c704d8 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,8 @@ +server { + listen 80; + + location / { + root /usr/share/nginx/html; + index index.html; + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..78c99df --- /dev/null +++ b/package.json @@ -0,0 +1,4 @@ +{ + "name": "notes-frontend", + "version": "1.0.0" +} \ No newline at end of file diff --git a/prepare-app.sh b/prepare-app.sh new file mode 100644 index 0000000..169a51d --- /dev/null +++ b/prepare-app.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker-compose build \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..241a744 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +fastapi +uvicorn +psycopg2-binary +sqlalchemy +pydantic + diff --git a/schemas.py b/schemas.py new file mode 100644 index 0000000..2a41a92 --- /dev/null +++ b/schemas.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel + +class NoteCreate(BaseModel): + content: str + +class NoteResponse(BaseModel): + id: int + content: str + + class Config: + from_attributes = True \ No newline at end of file diff --git a/secret.yaml b/secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..06d7405020018ddf3cacee90fd4af10487da3d20 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/service.yaml b/service.yaml new file mode 100644 index 0000000..57c7365 --- /dev/null +++ b/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: backend-service + namespace: notes-app +spec: + selector: + app: backend + ports: + - port: 80 + targetPort: 5000 +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-service + namespace: notes-app +spec: + type: NodePort + selector: + app: frontend + ports: + - port: 80 + targetPort: 80 + nodePort: 30007 \ No newline at end of file diff --git a/start-app.sh b/start-app.sh new file mode 100644 index 0000000..80b5727 --- /dev/null +++ b/start-app.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker-compose up -d \ No newline at end of file diff --git a/statefulset.yaml b/statefulset.yaml new file mode 100644 index 0000000..3d431d5 --- /dev/null +++ b/statefulset.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: postgres + namespace: notes-app +spec: + serviceName: postgres + replicas: 1 + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + spec: + containers: + - name: postgres + image: postgres:14 + env: + - name: POSTGRES_USER + value: user + - name: POSTGRES_PASSWORD + value: password + - name: POSTGRES_DB + value: notesdb + ports: + - containerPort: 5432 + volumeMounts: + - name: postgres-storage + mountPath: /var/lib/postgresql/data + volumeClaimTemplates: + - metadata: + name: postgres-storage + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +apiVersion: v1 +kind: Service +metadata: + name: postgres + namespace: notes-app +spec: + selector: + app: postgres + ports: + - port: 5432 + targetPort: 5432 \ No newline at end of file diff --git a/stop-app.sh b/stop-app.sh new file mode 100644 index 0000000..8bff4e7 --- /dev/null +++ b/stop-app.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker-compose down \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..56004c9 --- /dev/null +++ b/vite.config.js @@ -0,0 +1 @@ +export default {} \ No newline at end of file