Skip to content

manches3003/Node_blog_application

Repository files navigation

πŸ“ Node Blog Application

A full-stack blog application built with Node.js + Express + React, deployed through a complete DevOps pipeline β€” Docker, Kubernetes (Minikube), Horizontal Pod Autoscaling, CI/CD via GitHub Actions, and load-tested with k6.

This project reimplements a Python/Flask CRUD service from scratch in the Node.js ecosystem and takes it through the entire DevOps lifecycle.


🌐 Live Demo

Run locally via Minikube β€” see Getting Started below.

Docker Hub Image: manches300/node-blog-app:latest


🧱 Tech Stack

Layer Technology
Backend Node.js 20, Express 4.18
Frontend React 19, Vite
Database PostgreSQL 15, Sequelize 6 ORM
Containerization Docker (multi-stage build), Docker Compose
Orchestration Kubernetes v1.28 (Minikube)
Autoscaling Horizontal Pod Autoscaler (HPA)
Load Testing k6
CI/CD GitHub Actions (self-hosted runner)

✨ Features

  • βœ… Full CRUD operations β€” Create, Read, Update, Delete blog posts
  • βœ… React SPA served directly from Express (single port 5000)
  • βœ… Multi-stage Docker build β€” lean Alpine-based runtime image
  • βœ… Kubernetes deployment with liveness & readiness probes
  • βœ… HPA β€” auto-scales from 2 to 10 replicas based on CPU/memory
  • βœ… Secrets management β€” sensitive config stored in Kubernetes Secrets, never in Git
  • βœ… Self-healing β€” pods replaced automatically within ~11 seconds of failure
  • βœ… CI/CD pipeline β€” automated build, push to Docker Hub, and deploy on every push to main

πŸ“ Project Structure

Node_blog_application/
β”œβ”€β”€ app/                    # Express backend source
β”œβ”€β”€ frontend/               # React + Vite frontend
β”œβ”€β”€ k8s/
β”‚   β”œβ”€β”€ deployment.yaml     # Kubernetes Deployment
β”‚   β”œβ”€β”€ service.yaml        # NodePort Service
β”‚   β”œβ”€β”€ hpa.yaml            # Horizontal Pod Autoscaler
β”‚   └── postgres.yaml       # PostgreSQL Deployment + ClusterIP Service
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── ci.yml          # GitHub Actions CI/CD pipeline
β”œβ”€β”€ loadtest.js             # k6 load test script
β”œβ”€β”€ Dockerfile              # Multi-stage Docker build
β”œβ”€β”€ docker-compose.yaml     # Local development stack
β”œβ”€β”€ app.js                  # Express entry point
└── .env.example            # Environment variable template

πŸš€ Getting Started

Prerequisites


Option 1 β€” Run with Docker Compose (Local Dev)

# Clone the repo
git clone https://github.com/manches3003/Node_blog_application.git
cd Node_blog_application

# Copy and configure environment variables
cp .env.example .env

# Start the full stack (app + postgres)
docker compose up --build

App will be available at http://localhost:5000

⚠️ If your database password contains @, it must be percent-encoded as %40 in the DATABASE_URL. See Notes below.


Option 2 β€” Deploy to Kubernetes (Minikube)

# Start Minikube
minikube start --driver=docker

# Enable metrics server (required for HPA)
minikube addons enable metrics-server

# Pull the image into Minikube
minikube image pull manches300/node-blog-app:latest

# Create Kubernetes Secret with your credentials
kubectl create secret generic node-blog-secrets \
  --from-literal=DATABASE_URL="postgresql://postgres:password@postgres:5432/node_blog_db" \
  --from-literal=SECRET_KEY="your-secret-key"

# Deploy PostgreSQL
kubectl apply -f k8s/postgres.yaml

# Deploy the application
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/hpa.yaml --server-side=true

# Wait for rollout
kubectl rollout status deployment node-blog-app --timeout=120s

# Get the app URL
minikube service node-blog-app --url

On Windows with Docker driver, keep the terminal open β€” the tunnel must stay active for the URL to remain accessible.


🌐 API Endpoints

Method Endpoint Description
GET /api/posts Get all posts
POST /api/posts Create a new post
GET /api/posts/:id Get a single post
PUT /api/posts/:id Update a post
DELETE /api/posts/:id Delete a post
GET /health Health check (used by probes)

βš™οΈ Kubernetes Architecture

Internet
    β”‚
    β–Ό
NodePort Service (port 30080)
    β”‚
    β–Ό
Deployment: node-blog-app
β”œβ”€β”€ Pod 1 (node-blog-app)  ─────┐
└── Pod 2 (node-blog-app)       β”œβ”€β”€ ClusterIP: postgres:5432
        β–²                       β”‚
        β”‚                       β–Ό
  HPA (min 2 / max 10)    PostgreSQL Pod
  CPU: 50% threshold
  Memory: 70% threshold

Resource limits per pod:

Request Limit
CPU 100m 500m
Memory 128Mi 256Mi

πŸ“Š Load Test Results (k6)

Tested with 500 concurrent virtual users over 100 seconds (5-stage ramp).

Metric Value Threshold Status
Total Requests 77,834 β€” βœ…
Throughput 771 req/s β€” βœ…
Avg Response Time 3.83 ms < 2000 ms βœ…
Median (p50) 1.66 ms β€” βœ…
p90 5.78 ms β€” βœ…
p95 12.05 ms < 2000 ms βœ…
Max Response Time 134.39 ms β€” βœ…
Error Rate 0.00% < 50% βœ…
Max Virtual Users 500 >= 500 βœ…

Run the load test yourself

# Install k6: https://k6.io/docs/get-started/installation/
k6 run loadtest.js

πŸ” CI/CD Pipeline

The GitHub Actions workflow (.github/workflows/ci.yml) triggers on every push to main:

  1. Test β€” Install dependencies, run npm test
  2. Build β€” Install frontend deps, run Vite build
  3. Docker β€” Login to Docker Hub, build & push manches300/node-blog-app:latest
  4. Deploy β€” Setup Minikube, apply all manifests via kubectl

A self-hosted GitHub Actions runner is required because standard hosted runners cannot run a Minikube cluster.


πŸ”’ Environment Variables

Copy .env.example to .env and fill in your values:

NODE_ENV=production
PORT=5000
DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@postgres:5432/node_blog_db
SECRET_KEY=your-secret-key-change-in-production

In Kubernetes, these are injected from the node-blog-secrets Secret β€” never committed to the repository.


πŸ“ Notes

Password URL Encoding

If your PostgreSQL password contains special characters like @, you must percent-encode them in the DATABASE_URL:

@ β†’ %40

Minikube Tunnel (Windows)

On Windows with the Docker driver, the terminal running minikube service node-blog-app --url must stay open. Closing it will make the URL inaccessible.

HPA and Metrics Server

The HPA requires the Minikube metrics-server addon. Enable it with:

minikube addons enable metrics-server

πŸ› Known Challenges & Fixes

Challenge Fix
ENOENT error on startup Dockerfile was copying frontend build to /app/public but app.js referenced /app/frontend/dist β€” fixed by aligning the static path
Docker token error in CI Docker Desktop access issue during GitHub Actions β€” regenerated the Docker Hub token
Minikube in GitHub Actions Standard hosted runners can't run Minikube β€” switched to a self-hosted runner
@ in DB password Percent-encoded as %40 in all DATABASE_URL values

πŸ‘¨β€πŸ’» Authors


πŸ“„ License

This project is for academic purposes. Feel free to reference or fork it for learning.


Made with β˜• and way too many kubectl get pods commands

About

Blog application with the help of node.js and react.js integrated it with the docker image and containerized it in kubernets.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors