Skip to main content

Capstone — Deploy Campus Library on Kubernetes

Time for the real thing. This challenge chains everything you learned into one small project. Plan for about one hour. If you get stuck, the answer to every step is already in the pages you've read.

Goal

By the end, you should have a multi-replica Campus Library app running on Kubernetes with a Service, ConfigMap, health checks, and the ability to scale and rollback.

Step 1 · The App​

Create a simple Node.js app that reads from environment variables:

Create the project
mkdir campus-library-k8s
cd campus-library-k8s
k8s/configmap.yaml
cat > k8s/configmap.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_NAME: "Campus Library"
APP_PORT: "3000"
EOF
k8s/deployment.yaml
cat > k8s/deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: campus-library
spec:
replicas: 3
selector:
matchLabels:
app: campus-library
template:
metadata:
labels:
app: campus-library
spec:
containers:
- name: web
image: node:20-alpine
command: ["node", "-e"]
args:
- |
const http = require('http');
const name = process.env.APP_NAME || 'Campus Library';
const port = process.env.APP_PORT || 3000;
const server = http.createServer((req, res) => {
if (req.url === '/health') return res.writeHead(200).end('OK');
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({app: name, status: 'running', hostname: require('os').hostname()}));
});
server.listen(port, () => console.log(name + ' on port ' + port));
ports:
- containerPort: 3000
envFrom:
- configMapRef:
name: app-config
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "250m"
EOF
k8s/service.yaml
cat > k8s/service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: campus-library-svc
spec:
selector:
app: campus-library
ports:
- port: 80
targetPort: 3000
type: NodePort
EOF

Step 2 · Deploy​

Apply everything
kubectl apply -f k8s/
configmap/app-config created
deployment.apps/campus-library created
service/campus-library-svc created
Verify Pods are running
kubectl get pods -l app=campus-library
NAME READY STATUS RESTARTS AGE
campus-library-7d4b8c9f-x2k4m 1/1 Running 0 15s
campus-library-7d4b8c9f-a9n3p 1/1 Running 0 15s
campus-library-7d4b8c9f-q8w2r 1/1 Running 0 15s

Step 3 · Test​

Test the app
curl $(minikube service campus-library-svc --url)
{"app":"Campus Library","status":"running","hostname":"campus-library-7d4b8c9f-x2k4m"}

The hostname changes on each request — traffic is load-balanced across all 3 Pods.

Step 4 · Scale​

Scale to 5
kubectl scale deployment campus-library --replicas=5
Verify
kubectl get pods -l app=campus-library
NAME READY STATUS RESTARTS AGE
campus-library-7d4b8c9f-x2k4m 1/1 Running 0 2m
campus-library-7d4b8c9f-a9n3p 1/1 Running 0 2m
campus-library-7d4b8c9f-q8w2r 1/1 Running 0 2m
campus-library-7d4b8c9f-m3j5n 1/1 Running 0 5s
campus-library-7d4b8c9f-k8p2w 1/1 Running 0 5s

Step 5 · Update and Rollback​

Update the ConfigMap
kubectl create configmap app-config --from-literal=APP_NAME="Campus Library v2" --dry-run=client -o yaml | kubectl apply -f -
Restart to pick up the new config
kubectl rollout restart deployment/campus-library
Test the update
curl $(minikube service campus-library-svc --url)
{"app":"Campus Library v2","status":"running","hostname":"..."}
Rollback if needed
kubectl rollout undo deployment/campus-library

Step 6 · Cleanup​

Delete everything
kubectl delete -f k8s/
Remember

This capstone chained: ConfigMap → Deployment → Service → health checks → scaling → rollout → rollback. This is exactly how production Kubernetes works.