Side-by-Side Testing (Canary)
Goal: validate a new version in isolation alongside production in a single cluster before committing to a full region rollout.
How it works
A canary release with Karmada primitives uses three object types:
- Base
Deployment— the stable version, propagated to all clusters by aPropagationPolicy. - Canary
Deployment— a separate Deployment running the new version, propagated to a single target cluster by its ownPropagationPolicy. Both Deployments share the sameServiceselector (app: http-probe-app), so traffic splits by pod count automatically. OverridePolicy— patches the base Deployment'sROLLOUT_LABELvalue on the target cluster, triggering a Kubernetes rolling update there to converge on the new version. Finalization applies the new version to the base manifest and removes all temporary resources.
Demo 1 — Canary in one cluster, promote to region
Validate the new version in member1 only before committing to the rest of the region.
member2 and member3 serve stable traffic throughout.
The following diagram depicts the full sequence of operations — from single-cluster canary deployment through promotion and region-wide finalization:
Step 1: Deploy a canary alongside the base on member1
Create a separate canary Deployment running version v2, propagated to member1 only.
http-probe-app-canary-member1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: http-probe-app-canary-member1
labels:
app: http-probe-app
version: canary
spec:
replicas: 1
selector:
matchLabels:
app: http-probe-app
version: canary-member1
template:
metadata:
labels:
app: http-probe-app
version: canary-member1
spec:
containers:
- name: http-probe-app
image: ghcr.io/cmontemuino/http-probe-test-app:v0.5.0
ports:
- containerPort: 8080
env:
- name: ROLLOUT_LABEL
value: v2
resources:
requests:
cpu: 25m
memory: 64Mi
limits:
cpu: 25m
memory: 64Mi
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: http-probe-app-canary-member1-propagation
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: http-probe-app-canary-member1
placement:
clusterAffinity:
clusterNames:
- member1
Two things to note:
- The canary Deployment uses an additional label
version: canary-member1on its pod template. This label is not present in the base Deployment's pod template, so the canary pods are distinct from the base pods. However, both share theapp: http-probe-applabel, which is all the Service selector matches — so traffic is distributed across all pods from both Deployments proportionally. - The canary
PropagationPolicyselects onlyhttp-probe-app-canary-member1by name, targetingmember1only. The basePropagationPolicyis unaffected — it continues propagating the base Deployment to all three clusters.
kubectl apply -f canary/http-probe-app-canary-member1.yaml
Verify the canary Deployment was created and propagated:
kubectl get deployment http-probe-app-canary-member1
Expected output:
NAME READY UP-TO-DATE AVAILABLE AGE
http-probe-app-canary-member1 1/1 1 1 2m44s
kubectl get resourcebinding http-probe-app-canary-member1-deployment
Expected output:
NAME SCHEDULED FULLYAPPLIED AGE
http-probe-app-canary-member1-deployment True True 2m48s
At this point member1 is running 2 base pods (v1) and 1 canary pod (v2), for 3 pods
total. member2 and member3 run only their 2 base pods. Approximately 1 in 3 requests to
member1 will be served by the canary.
What to observe in the dashboard:
- Replica panel: a new canary pod (yellow
●) appears in themember1column alongside the 2 existing stable pods (green○). Themember2andmember3columns show only stable pods — the canaryPropagationPolicytargetsmember1only. - Traffic panel: the
member1column begins showing yellow-highlighted responses as requests land on the canary pod. The ratio of yellow to white responses reflects the 1 canary pod out of 3 total pods onmember1.