Canary-Deployments: Schrittweise Rollouts richtig gemacht
Canary-Deployments leiten einen Teil des Traffics auf die neue Version und rollen bei steigenden Fehlerraten automatisch zurück — so geht es sicher.

Blue-Green-Deployments schalten 100 % des Traffics auf einen Schlag um. Das ist in Ordnung, wenn deine Smoke-Tests alles abfangen, aber manche Fehler treten nur unter echten Traffic-Mustern auf. Canary-Deployments gehen vorsichtiger vor: Ein kleiner Prozentsatz des Traffics wird auf die neue Version geleitet, zentrale Metriken werden überwacht und der Prozentsatz schrittweise erhöht — oder bei Problemen automatisch zurückgerollt.
Der Canary-Prozess
Ein Canary-Deployment folgt einem progressiven Rollout: Beginne mit 1–5 % des Traffics, beobachte ein Zeitfenster lang, erhöhe den Prozentsatz, wenn die Metriken gesund sind, und wiederhole das Ganze bis 100 %.
interface CanaryStage {
percentage: number;
durationMinutes: number;
metrics: MetricCheck[];
}
interface MetricCheck {
name: string;
query: string;
threshold: number;
comparison: "less_than" | "greater_than";
}
const canaryPlan: CanaryStage[] = [
{
percentage: 5,
durationMinutes: 10,
metrics: [
{ name: "error_rate", query: "rate(http_5xx[5m])/rate(http_total[5m])", threshold: 0.01, comparison: "less_than" },
{ name: "p99_latency", query: "histogram_quantile(0.99, rate(http_duration_bucket[5m]))", threshold: 2.0, comparison: "less_than" },
],
},
{
percentage: 25,
durationMinutes: 15,
metrics: [
{ name: "error_rate", query: "rate(http_5xx[5m])/rate(http_total[5m])", threshold: 0.01, comparison: "less_than" },
{ name: "p99_latency", query: "histogram_quantile(0.99, rate(http_duration_bucket[5m]))", threshold: 2.0, comparison: "less_than" },
],
},
{
percentage: 50,
durationMinutes: 15,
metrics: [
{ name: "error_rate", query: "rate(http_5xx[5m])/rate(http_total[5m])", threshold: 0.01, comparison: "less_than" },
{ name: "p99_latency", query: "histogram_quantile(0.99, rate(http_duration_bucket[5m]))", threshold: 2.0, comparison: "less_than" },
],
},
{ percentage: 100, durationMinutes: 0, metrics: [] },
];Traffic-Aufteilung mit Nginx
Die split_clients-Direktive von Nginx leitet einen deterministischen Prozentsatz des Traffics anhand einer Client-Kennung auf den Canary.
# ❌ Random routing — same user might flip between versions
upstream canary { server canary-1:3000; server canary-2:3000; }
upstream stable { server stable-1:3000; server stable-2:3000; }
# ✅ Consistent routing — same user always hits the same version
split_clients "$remote_addr$uri" $upstream_variant {
5% canary;
* stable;
}
upstream canary { server canary-1:3000; server canary-2:3000; }
upstream stable { server stable-1:3000; server stable-2:3000; }
server {
listen 80;
location / {
proxy_pass http://$upstream_variant;
# Add header so downstream services know which version handled the request
proxy_set_header X-Deployment-Version $upstream_variant;
}
}Automatisierter Metrikvergleich
Der Canary-Release-Controller vergleicht die Metriken zwischen der Canary- und der stabilen Version. Wenn die Fehlerrate oder Latenz des Canaries deutlich schlechter ist, löst er einen automatischen Rollback aus.
interface MetricComparison {
metric: string;
canaryValue: number;
stableValue: number;
degradation: number;
acceptable: boolean;
}
async function compareCanaryMetrics(
canarySelector: string,
stableSelector: string,
window: string
): Promise<MetricComparison[]> {
const comparisons: MetricComparison[] = [];
// Compare error rates
const canaryErrors = await queryPrometheus(
`rate(http_errors_total{deployment="${canarySelector}"}[${window}])`
);
const stableErrors = await queryPrometheus(
`rate(http_errors_total{deployment="${stableSelector}"}[${window}])`
);
const errorDegradation = stableErrors > 0
? (canaryErrors - stableErrors) / stableErrors
: canaryErrors > 0 ? 1 : 0;
comparisons.push({
metric: "error_rate",
canaryValue: canaryErrors,
stableValue: stableErrors,
degradation: errorDegradation,
acceptable: errorDegradation < 0.10, // Less than 10% worse
});
// Compare p99 latency
const canaryLatency = await queryPrometheus(
`histogram_quantile(0.99, rate(http_duration_bucket{deployment="${canarySelector}"}[${window}]))`
);
const stableLatency = await queryPrometheus(
`histogram_quantile(0.99, rate(http_duration_bucket{deployment="${stableSelector}"}[${window}]))`
);
const latencyDegradation = stableLatency > 0
? (canaryLatency - stableLatency) / stableLatency
: 0;
comparisons.push({
metric: "p99_latency",
canaryValue: canaryLatency,
stableValue: stableLatency,
degradation: latencyDegradation,
acceptable: latencyDegradation < 0.15, // Less than 15% worse
});
return comparisons;
}Kubernetes-Canary mit Istio
Das VirtualService von Istio bietet eine feingranulare Traffic-Aufteilung für Kubernetes-Deployments.
# Istio VirtualService — 5% canary split
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api-server
spec:
hosts:
- api-server
http:
- route:
- destination:
host: api-server
subset: stable
weight: 95
- destination:
host: api-server
subset: canary
weight: 5
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: api-server
spec:
host: api-server
subsets:
- name: stable
labels:
version: v1.2.0
- name: canary
labels:
version: v1.3.0Wann Canary vs. Blue-Green
| Criteria | Canary | Blue-Green |
|-----------------------|-------------------------------|-------------------------|
| Risk tolerance | Lower (gradual exposure) | Higher (all-at-once) |
| Rollback speed | Fast (reduce to 0%) | Instant (switch back) |
| Infrastructure cost | Minimal (small canary fleet) | Double (two full envs) |
| Metric comparison | Side-by-side during rollout | Before/after only |
| Complexity | Higher (traffic splitting) | Lower (DNS/LB switch) |
| Best for | High-traffic, risk-averse | Low-traffic, simple |Die wichtigsten Erkenntnisse
- Canary-Deployments reduzieren den Blast Radius — die neue Version wird vor dem vollständigen Rollout nur einem kleinen Teil der Nutzer ausgesetzt
- Konsistentes Routing verwenden — derselbe Nutzer sollte während der Canary-Phase immer auf derselben Version landen
- Metrikvergleich automatisieren — vergleiche die Fehlerraten und Latenzen von Canary und stabiler Version, nicht nur absolute Schwellenwerte
- Rollback-Auslöser vor dem Start definieren — ein automatischer Rollback bei Metrikverschlechterung verhindert menschliches Zögern
- Traffic schrittweise erhöhen — 5 % → 25 % → 50 % → 100 % bietet mehrere Beobachtungsfenster
- Canary findet, was Tests übersehen — manche Fehler zeigen sich nur unter echten Traffic-Mustern und echten Daten


