This project demonstrates a Canary Deployment in Kubernetes without using a service mesh.
A canary deployment lets you release a new version of your application to a small percentage of users before rolling it out to everyone.
A canary deployment is a rollout strategy where:
- Most users get the stable (old) version
- A few users get the new (canary) version
If everything works well → promote the canary If something breaks → roll back quickly
- Node.js (simple backend app)
- Docker (containerization)
- Minikube (local Kubernetes cluster)
- kubectl (Kubernetes CLI)
- YAML (Kubernetes manifests)
Repository root:
app_v1.js# Stable application (v1)app_v2.js# Canary application (v2)Dockerfile-v1# Dockerfile for v1Dockerfile-v2# Dockerfile for v2deployment_v1.yaml# Stable Kubernetes deployment (v1)deployment_v2.yaml# Canary Kubernetes deployment (v2)services.yaml# Kubernetes Servicepackage.json# Node.js dependenciesREADME.md# This filescreenshots/# Proof and screenshots (optional)
Version 1 (Stable) — app_v1.js
const express = require('express')
const app = express()
app.get("/",(req,res)=>{
res.send("It is the Stable Version")
})
app.listen(8080, ()=>console.log("Stable V1 is running"))Version 2 (Canary) — app_v2.js
const express = require('express')
const app = express()
app.get("/",(req,res)=>{
res.send("It is the canary Version")
})
app.listen(8080, ()=> console.log("Canary V2 is running"))Dockerfile-v1
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY app_v1.js .
EXPOSE 8080
CMD ["node","app_v1.js"]Dockerfile-v2
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY app_v2.js .
EXPOSE 8080
CMD ["node","app_v2.js"]Run:
docker build -f Dockerfile-v1 -t <yourhub>/canary-app:v1 .
docker push <yourhub>/canary-app:v1
docker build -f Dockerfile-v2 -t <yourhub>/canary-app:v2 .
docker push <yourhub>/canary-app:v2(Replace <yourhub> with your Docker Hub username or registry.)
deployment_v1.yaml (Stable)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-v1
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: <yourhub>/canary-app:v1
ports:
- containerPort: 8080deployment_v2.yaml (Canary)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-v2
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: <yourhub>/canary-app:v2
ports:
- containerPort: 8080services.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: NodePort
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
nodePort: 30080kubectl apply -f deployment_v1.yaml
kubectl apply -f deployment_v2.yaml
kubectl apply -f services.yamlCheck pods:
kubectl get podsYou should see:
- 3 pods → v1 (stable)
- 1 pod → v2 (canary)
minikube service myapp-service --urlOpen the generated URL in your browser. Refresh multiple times — you should mostly see the stable version and occasionally the canary.
If the canary has issues:
kubectl delete deployment app-v2Now 100% of traffic goes to the stable version (v1).
If the canary is successful:
kubectl set image deployment/app-v1 app=<yourhub>/canary-app:v2
kubectl delete deployment app-v2Now 100% of users receive version v2.
Below are the screenshots (files under screenshots/). If you don't have them yet, add PNGs with these names and they will render.
Output of kubectl get pods
Output of kubectl describe svc myapp-service
Output of minikube service myapp-service --url
Output of while true; do curl <url>; echo; sleep 0.5; done
Output of Rollback
Output of Promote
Docker images pushed
This project demonstrates:
- Canary deployment
- Traffic splitting without a service mesh
- Multi-version Kubernetes deployment
- Rollback and promotion strategies
Dhruv Sharma B.Tech — JK Lakshmipat University






