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.