Ich wollte eine neue Version meiner App mit zwanzig Prozent des Traffics testen. Also habe ich meine Azure Container App auf mehrere Revisionen umgestellt, die neue Version deployt und 200 Requests geschickt. Die neue Version hat alle 200 beantwortet.
Dieser Explainer zeigt, wie Container Apps entscheidet, welche Revision einen Request beantwortet, wie Sie einen echten 80/20-Split bekommen, was dieser Split für einen einzelnen Nutzer bedeutet und was eine alte Revision bei null Prozent noch tat. Alles hier stammt aus einem echten Durchlauf in meinem eigenen Azure-Abonnement. Das Video ist auf Englisch.
Die wichtigsten Punkte
- Der Single-Revision-Modus kann nicht aufteilen. Er ist der Standard: eine aktive Revision zur Zeit, ein Deploy ist das Release. Gewichte setzen schlägt fehl mit „configured for single revision“.
- Der Multiple-Revision-Modus hält eine neue Version nicht zurück. Die Standard-Traffic-Regel ist
latestRevision: truemit 100 %. Sie zeigt auf die jeweils neueste Revision, also übernimmt jedes Deploy den gesamten Traffic, sobald es bereit ist. Benennen Sie die Revisionen in den Gewichten, bevor Sie deployen, dann startet eine neue Revision bei null. - 80/20 gilt pro Request, nicht pro Nutzer. 1.000 Requests teilten sich 806 / 194. Ein Client auf einer Keep-Alive-Verbindung sah beide Versionen. Sticky Sessions gibt es nur im Single-Revision-Modus. Für Tester gibt ein Label einer Revision eine eigene Adresse.
- Jede aktive Revision betreibt ihre eigenen Replicas. Bei 30 Requests pro Sekunde liefen bei einer Revision fünf Replicas, bei zwei Revisionen mit 50/50 zwei plus drei. Eine Revision bei null Prozent behielt viereinhalb Minuten lang vier Replicas und danach ihr Minimum von einer, bis ich sie deaktiviert habe.
Eine Revision zur Zeit
Jede Änderung am Container (ein neues Image, eine neue Umgebungsvariable, eine neue Scale-Regel: alles im template der App) erzeugt eine neue Revision, einen unveränderlichen Snapshot der App. Jede Revision läuft als Replicas, Kopien Ihres Containers. Änderungen an der configuration der App (Secrets, Ingress, Traffic-Regeln, Labels) erzeugen keine Revision.
Standardmäßig läuft eine Container App im Single-Revision-Modus: eine aktive Revision zur Zeit. Als ich Version zwei deployt habe, hat v2 den gesamten Traffic übernommen, sobald sie bereit war, und kurz danach wurde v1 automatisch deaktiviert. In diesem Modus ist ein Deploy das Release.
Ich habe trotzdem einen Split angefordert, 80 % für v1 und 20 % für v2:
> az containerapp ingress traffic set -n shop -g rg-demo --revision-weight shop--v1=80 shop--v2=20ERROR: Containerapp 'shop' is configured for single revision. Set revision mode to multiple in order to set ingress traffic.
Eine aktive Revision heißt: Es gibt nichts aufzuteilen.
Die neueste bekommt alles
Der Multiple-Revision-Modus erlaubt mehrere aktive Revisionen gleichzeitig, und Sie entscheiden, wie sie sich den Traffic teilen. Ein Befehl stellt den Modus um:
az containerapp revision set-mode -n shop -g rg-demo --mode multiple
Dann habe ich v3, meinen Canary, genauso deployt wie vorher. v2 war daneben weiter aktiv. 200 Requests später hatte v3 alle 200 beantwortet. Die Traffic-Regeln haben gezeigt, warum:
> az containerapp ingress traffic show -n shop -g rg-demo[{"latestRevision": true,"weight": 100}]
Das ist der Standard. Die Regel nennt keine Revision, sie zeigt auf die jeweils neueste. Der Multiple-Modus hat v2 nur neben der neuen weiterlaufen lassen.
Die Lösung: Revisionen benennen. Erst die Gewichte per Revisionsname festlegen, dann deployen, dann die Gewichte selbst verschieben:
az containerapp ingress traffic set -n shop -g rg-demo \--revision-weight shop--v2=100az containerapp update -n shop -g rg-demo \--set-env-vars APP_VERSION=v3 --revision-suffix v3az containerapp ingress traffic set -n shop -g rg-demo \--revision-weight shop--v2=80 shop--v3=20
Später in meinem Durchlauf, während die Gewichte noch v2 und v3 benannten, habe ich v4 deployt: Sie wurde mit einer Replica aktiv und bekam 0 % des Traffics.
| Single-Revision-Modus | Multiple-Revision-Modus | |
|---|---|---|
| Aktive Revisionen | eine | so viele, wie Sie aktiv lassen |
| Ein neues Deploy | übernimmt den gesamten Traffic, sobald bereit; die alte wird deaktiviert | Standardregel: die neueste bekommt 100 %, sobald bereit; benannte Gewichte: startet bei 0 % |
| Traffic-Splitting | abgelehnt | per Gewicht (Revisionsname oder Label) |
| Sticky Sessions | verfügbar | nicht verfügbar |
| Alte Revisionen | werden für Sie deaktiviert | laufen weiter, bis Sie sie deaktivieren |
Die Doku nennt einen dritten Modus, Deployment Labels (Preview): Labels wie stage und prod bekommen neue Revisionen zugewiesen, und alte werden abgeschaltet, wenn kein Label mehr auf sie zeigt.
Zwanzig Prozent wovon?
Mit den Gewichten 80 und 20 habe ich 1.000 Requests geschickt, jeden über eine neue Verbindung: 806 für v2, 194 für v3. Nah an 80/20, nicht exakt: Jeder Request wird für sich zufällig nach den Gewichten verteilt.
Dann ein Nutzer: ein Client, eine Keep-Alive-Verbindung, zehn Requests nacheinander. Er sah v2 v2 v2 v3 v2 v3 v2 v2 v2 v2. Der Split gilt pro Request, nicht pro Nutzer. Session-Affinität (Sticky Sessions) wird nur im Single-Revision-Modus unterstützt. Wenn ein Nutzer bei einer Version bleiben muss, reichen die Gewichte allein nicht.
Für Tester gibt es ein Label. Ein Label gibt einer Revision eine eigene Adresse, unabhängig von den Gewichten:
az containerapp revision label add -n shop -g rg-demo \--label canary --revision shop--v3
Die Adresse des Labels ist der App-Name, drei Bindestriche, das Label, dann die Domain der Container-Apps-Umgebung: https://shop---canary.<env-domain>.westeurope.azurecontainerapps.io/. Sie hat jedes Mal v3 geantwortet, 100 von 100 Aufrufen, während v3 weiter 20 % des normalen Traffics hatte. Ein Label kann auch auf einer Revision bei 0 % liegen, so testen Sie, bevor echte Nutzer sie sehen. Echte Nutzer folgen den Gewichten. Tester nutzen das Label.
Jedes Gate hat seine eigene Crew
Jede aktive Revision hat ihre eigenen Replicas, und jede skaliert nach ihrem eigenen Anteil an den Requests. Meine HTTP-Scale-Regel verlangte etwa eine Replica pro zehn Requests pro Sekunde (--scale-rule-http-concurrency 10).
| 30 Requests/s für 3 Minuten | v2 | v3 | Summe |
|---|---|---|---|
| v3 bei 100 % | 4 (übrig, 0 % Traffic) | 5 | 9 |
| 50 / 50 (nach dem Herunterskalieren) | 2 | 3 | 5 |
Fünfzig-fünfzig aufgeteilt brauchte dieselbe Last fünf Replicas, genauso viele wie eine Revision allein. Der Split selbst hat in meinem Durchlauf keine zusätzlichen Replicas gekostet; das Modul warnt, dass er es kann, weil jede Revision ihr eigenes Minimum behält und für sich aufrundet. Was sich summiert, ist jede Revision, die Sie aktiv lassen.
Die alte Revision bei null Prozent
Als ich v2 auf 0 % gesetzt habe, hatte sie noch vier Replicas von den tausend Requests davor. Die behielt sie viereinhalb Minuten, dann zwei, und acht Minuten nachdem sie ihren Traffic verloren hatte, eine. Und die eine bleibt: Das ist die minimale Replica-Anzahl, die ich der App gegeben habe, und jede aktive Revision behält sie. Null Prozent Traffic heißt nicht null Replicas.
Am Ende habe ich die Revisionen deaktiviert, die ich nicht mehr brauchte:
az containerapp revision deactivate -n shop -g rg-demo --revision shop--v4
Eine inaktive Revision betreibt keine Replicas und kostet nichts (Container Apps behält bis zu 100 davon, Sie können eine wieder aktivieren).
Setzen Sie das Gewicht vor dem Deaktivieren auf null. In meinem Durchlauf hat revision deactivate auch bei einer Revision funktioniert, die noch 50 % des Gewichts hatte. Die Requests gingen sofort an die andere Revision (200 von 200, auch zwei Minuten später), aber die Traffic-Liste zeigte die inaktive Revision weiter mit 50 %, bis ich die Gewichte neu gesetzt habe.
Was beim Ausprobieren passiert ist
Getestet am 21. Oktober 2026 in meinem eigenen Azure-Abonnement (westeurope, Azure CLI 2.88.0); danach wurde alles gelöscht. Die App ist meine eigene kleine Python-API, die {"version": "v3", ...} antwortet; eine neue Version ist ein neuer Wert von APP_VERSION plus ein Revision-Suffix. split.py, ebenfalls von mir, hat gezählt, welche Version antwortet, einen Nutzer auf einer Verbindung gespielt, Last mit fester Rate geschickt und die Replicas jeder aktiven Revision abgefragt. Die Umgebung brauchte 17,5 Minuten, jedes Update etwa 20 Sekunden plus 15 Sekunden, bis die neue Revision lief.
Nach v3 im Multiple-Modus, nichts festgelegt:
> az containerapp revision list -n shop -g rg-demo -o tableActive Replicas TrafficWeight NameTrue 1 0 shop--v2True 1 100 shop--v3> python split.py --app shop --rg rg-demo send 200200 requests to the app URL in 4 sv3 200 100.0 %
Der 80/20-Split, 1.000 Requests und ein Nutzer:
> python split.py --app shop --rg rg-demo send 10001000 requests to the app URL in 18 sv2 806 80.6 %v3 194 19.4 %> python split.py --app shop --rg rg-demo user 10one client, one connection, 10 requests:v2 v2 v2 v3 v2 v3 v2 v2 v2 v2v2: 8, v3: 2
Das Label:
> curl.exe -s https://shop---canary.<env-domain>.westeurope.azurecontainerapps.io/{"version": "v3", "replica": "?"}
v4 deployt, während die Gewichte v2 und v3 benannten:
Active Replicas TrafficWeight NameTrue 2 50 shop--v2True 3 50 shop--v3True 1 0 shop--v4
v2 bei 0 % nach dem Lasttest (mein Tool fragte alle 15 Sekunden ab):
2 s shop--v2 4 repl. (0 %) · shop--v3 5 repl. (100 %)53 s shop--v2 2 repl. (0 %) · shop--v3 5 repl. (100 %)277 s shop--v2 1 repl. (0 %) · shop--v3 4 repl. (100 %)517 s shop--v2 1 repl. (0 %) · shop--v3 1 repl. (100 %)
Das Deaktivieren mit verbliebenem Gewicht:
> az containerapp revision list -n shop -g rg-demo --all -o tableActive Replicas TrafficWeight NameTrue 6 50 shop--v3False 0 50 shop--v4
Und ein Detail: Direkt nach containerapp create mit Revision-Suffix zeigte die Liste eine zusätzliche, automatisch benannte Revision (shop--ttolvpb, aktiv, eine Replica, 0 %) neben shop--v1; beim nächsten Deploy war sie inaktiv.





