Canary Deployments¶
Overview¶
The Varnish Gateway supports weighted traffic splitting via the standard Gateway API weight field in BackendRef. Use this for canary deployments and A/B testing.
Weight Calculation¶
Weights are not percentages Traffic distribution:
Example: weights 90/10 → 90% and 10% traffic split
When a service has multiple pods, each pod inherits the same weight. With 2 stable pods (weight 90) and 2 canary pods (weight 10), you get total weights of 180/20 = 90%/10% split. The ratio is preserved.
Example¶
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
spec:
parentRefs:
- name: varnish-gateway
hostnames:
- "app.example.com"
rules:
- backendRefs:
- name: app-stable
port: 8080
weight: 90
- name: app-canary
port: 8080
weight: 10
This routes 90% of requests to app-stable service and 10% to app-canary.
Progressive Rollout¶
Gradually increase canary weight:
- Start:
weight: 1(1% traffic) - If stable:
weight: 10(10% traffic) - If stable:
weight: 25(25% traffic) - If stable:
weight: 50(50% traffic) - Complete: Remove stable backend or flip weights
Testing¶
# Make 100 requests and count responses
for i in {1..100}; do curl -H "Host: app.example.com" http://GATEWAY_IP/; done | sort | uniq -c
Monitoring¶
# Check backend health and request counts
kubectl exec -it deploy/varnish-gateway -- varnishadm backend.list -p
Complete working example¶
The manifest below deploys a Gateway, two backend Deployments (app-stable running
hashicorp/http-echo with text stable-v1.0, and app-canary with text
canary-v2.0), their Services, and an HTTPRoute that splits traffic 90/10.
---
# Gateway (if not already deployed)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: varnish-gateway
namespace: default
spec:
gatewayClassName: varnish
listeners:
- name: http
protocol: HTTP
port: 80
---
# Stable backend deployment (version 1.0)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-stable
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
version: stable
template:
metadata:
labels:
app: myapp
version: stable
spec:
containers:
- name: app
image: hashicorp/http-echo
args:
- "-text=stable-v1.0"
- "-listen=:8080"
ports:
- containerPort: 8080
---
# Canary backend deployment (version 2.0)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-canary
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
version: canary
template:
metadata:
labels:
app: myapp
version: canary
spec:
containers:
- name: app
image: hashicorp/http-echo
args:
- "-text=canary-v2.0"
- "-listen=:8080"
ports:
- containerPort: 8080
---
# Stable service
apiVersion: v1
kind: Service
metadata:
name: app-stable
namespace: default
spec:
selector:
app: myapp
version: stable
ports:
- port: 8080
targetPort: 8080
---
# Canary service
apiVersion: v1
kind: Service
metadata:
name: app-canary
namespace: default
spec:
selector:
app: myapp
version: canary
ports:
- port: 8080
targetPort: 8080
---
# HTTPRoute with weighted traffic split (90% stable, 10% canary)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
namespace: default
spec:
parentRefs:
- name: varnish-gateway
namespace: default
hostnames:
- "app.example.com"
rules:
- backendRefs:
- name: app-stable
port: 8080
weight: 90
- name: app-canary
port: 8080
weight: 10
Save as canary.yaml and apply with kubectl apply -f canary.yaml. Verify the split: