Skip to main content

Command Palette

Search for a command to run...

Project 4.4: Web Caching Fallback (E-commerce App)

Published
โ€ข6 min read
M

I am pursuing a Master's in Communication Systems and Networks at the Cologne University of Applied Sciences, Germany.

๐Ÿงฐ PREREQUISITES:

  • EC2 Instance: t2.medium (Ubuntu 24.04)

  • Security Group: Open port 30000-32767 for NodePort

๐Ÿ”ง STEP 1: Install Docker, Minikube, kubectl

1. Install Docker

sudo apt update -y
sudo apt install -y docker.io curl
sudo systemctl enable docker
sudo systemctl start docker

2. Add user to Docker group

sudo usermod -aG docker $USER
newgrp docker  # or logout and log in again

3. Install Minikube

bashCopyEditcurl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
rm minikube-linux-amd64

4. Install kubectl

K8S_VERSION=$(curl -s https://dl.k8s.io/release/stable.txt)
curl -LO https://dl.k8s.io/release/${K8S_VERSION}/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

๐Ÿš€ STEP 2: Start Minikube

Start Minikube with enough resources

minikube start --driver=docker --memory=3072mb --cpus=2

Use Minikube Docker for image build

bashCopyEditeval $(minikube docker-env)

๐Ÿ›  STEP 3: Build Node.js E-commerce App

1. Create index.js

vim index.js

Paste:

๐Ÿ›  STEP 3: Build Node.js E-commerce App

1. Create index.js

vim index.js

Paste:

const express = require('express');
const app = express();
app.use(express.json());

let products = [
  { id: 1, name: "Laptop", price: 999 },
  { id: 2, name: "Phone", price: 599 }
];

app.get('/products', (req, res) => res.json(products));

app.post('/products', (req, res) => {
  const product = req.body;
  product.id = products.length + 1;
  products.push(product);
  res.status(201).json({ message: 'Product added' });
});

app.listen(3000, () => console.log('E-commerce app running on port 3000'));

2. Create package.json

vim package.json

Paste:

{
  "name": "node-ecommerce",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "express": "^4.18.2"
  }
}

3. Create Dockerfile

vim Dockerfile

Paste:

FROM node:18
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

4. Build Docker image

docker build -t node-ecommerce:latest .

๐ŸŒ STEP 4: Set Up Nginx Caching

1. Create config folder and file

mkdir nginx
cd nginx
vim default.conf

Paste:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10m;
server {
    listen 8080;
    location / {
        proxy_pass http://localhost:3000;
        proxy_cache my_cache;
        proxy_cache_valid 200 10s;
        add_header X-Proxy-Cache $upstream_cache_status;
    }
}

โš™๏ธ STEP 5: Kubernetes Files

1. Create deployment.yaml

vim deployment.yaml

Paste:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ecommerce-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ecommerce
  template:
    metadata:
      labels:
        app: ecommerce
    spec:
      containers:
      - name: node-app
        image: node-ecommerce:latest
        imagePullPolicy: Never  # Use local image in Minikube
        ports:
        - containerPort: 3000
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/conf.d/
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config

2. Create service.yaml

vim service.yaml

Paste:

apiVersion: v1
kind: Service
metadata:
  name: ecommerce-service
spec:
  selector:
    app: ecommerce
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: NodePort

๐Ÿงฑ STEP 6: Deploy App to Minikube

1. Create ConfigMap for Nginx

kubectl create configmap nginx-config --from-file=nginx/default.conf
eval $(minikube docker-env)

2. Apply Deployment and Service

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

3. Check pod and service

kubectl get pods
kubectl get svc

๐ŸŒ STEP 7: Access the App

Open service

minikube service ecommerce-service

or manually:

curl -i http://<minikube-ip>:<nodeport>/products

curl -i http://192.168.49.2:30993/products

โœ… You should see a list of products and:

X-Proxy-Cache: MISS

๐Ÿ” STEP 8: Test Fallback Caching

1. Make a request to /products twice:

curl -i http://<minikube-ip>:<port>/products

Second time โ†’ You should see:

X-Proxy-Cache: HIT

๐Ÿ” How to See HIT Instead of EXPIRED

Immediately run this within 10 seconds:

curl -i http://192.168.49.2:30993/products

You should now get:

X-Proxy-Cache: HIT

2. Kill Node.js container

kubectl get pods
kubectl exec -it <pod-name> -c node-app -- kill 1
# kubectl exec -it ecommerce-app-5d9d64c87d-d5xs4 -c node-app -- kill 1

3. Make request again

curl -i http://<minikube-ip>:<port>/products
#curl -i http://192.168.49.2:30993/products

โœ… You should still get data from cache:

X-Proxy-Cache: HIT

๐Ÿ“˜ Revised Project Report for 4.4 โ€“ Fallback by Means of Web Caching


Title:

4.4 Fallback by Means of Web Caching


Focus Area:

๐Ÿ›ก๏ธ Resilience in microservice communication


Description:

System X consists of several microservices. These services communicate via an intermediate HTTP server, specifically an Nginx proxy. The aim of this project is to implement a fallback mechanism using web caching to maintain service availability when a backend service becomes temporarily unavailable.


Research Questions:

  1. Is web caching a suitable fallback solution for microservices?

  2. What are the pitfalls of relying on caching during failures?

  3. How should Nginx be configured for optimal caching in Kubernetes?

  4. What HTTP cache headers must be handled at the application layer (Node.js)?


Approach:

  • Deploy Nginx as a sidecar container within the same Kubernetes Pod of the backend microservice.

  • Let all outgoing and incoming HTTP traffic be proxied by Nginx.

  • Use Nginx caching directives and shared volumes to store and serve cached content.

  • Implement cache headers and control behavior in Node.js (Express) application.

  • Simulate service failure and observe whether Nginx can continue to serve cached data.


Technology Stack:

  • Kubernetes: Minikube for local orchestration

  • Docker: Containerization of Node.js app

  • Nginx: HTTP caching and proxying

  • Node.js (Express): E-commerce microservice

  • Ubuntu 24.04 on EC2 (t2.medium instance)


Architecture Diagram:

[Kubernetes Pod]
 โ”œโ”€โ”€ Container 1: Node.js (API)
 โ””โ”€โ”€ Container 2: Nginx (Sidecar Proxy)
        โ†“
     [Client Requests]
        โ†“
     Nginx (cache / proxy)
        โ†“
     Node.js App

Implementation Summary:

  • Created a simple /products API with GET and POST in Node.js.

  • Configured Nginx with proxy_cache, proxy_cache_path, and proxy_cache_valid for 10s duration.

  • Built both containers and deployed to the same Pod using Kubernetes.

  • ConfigMap mounted for Nginx configuration.

  • Kubernetes NodePort service exposed the app externally.


Tested Scenarios:

TestExpected ResultOutcome
First GET /productsFetch from backendโœ… MISS
Second GET /products <10sServe from cacheโœ… HIT
Backend container killedServe cached contentโœ… HIT
After 10s with backend downCache expired, failsโœ… EXPIRED

Findings:

  • โœ… Caching works reliably within timeout period.

  • โœ… Can handle short-term service outages without affecting client.

  • โš ๏ธ Stale data risk if cache duration is too long.

  • โš ๏ธ Requires manual cache control headers in backend (e.g., ETag, Cache-Control).


Nginx Configuration Sample:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10m;
server {
    listen 8080;
    location / {
        proxy_pass http://localhost:3000;
        proxy_cache my_cache;
        proxy_cache_valid 200 10s;
        add_header X-Proxy-Cache $upstream_cache_status;
    }
}

HTTP Header Setup in Node.js (if extended):

res.set('Cache-Control', 'public, max-age=10');
res.set('ETag', generateETag(data)); // optional

Conclusion:

Web caching using Nginx as a sidecar is an effective short-term fallback for microservices. It reduces downtime impact, increases perceived uptime, and simplifies load handling during failure spikes. However, developers must carefully manage cache invalidation and header configurations to avoid stale or incorrect data.