Ich habe 200 Nachrichten in eine Azure Storage Queue gelegt, für einen Worker auf Azure Container Apps. 22 Minuten lang wurde keine einzige verarbeitet. Zwei Korrekturen später haben zehn Replicas dieselbe Queue in etwa zwei Minuten geleert.
Dieser Explainer zeigt, wie eine Container App erfährt, dass Nachrichten warten (gar nicht: KEDA zählt sie für sie), welche zwei Dinge meinem Worker gefehlt haben und wo der eigentliche Fehler steckte. Alles hier stammt aus einem echten Durchlauf in meinem eigenen Azure-Abonnement. Das Video ist auf Englisch.
Die wichtigsten Punkte
- Ohne Scale-Regel zählt niemand Ihre Queue. Ein Worker ohne Ingress bekommt keine HTTP-Requests, die Standard-HTTP-Regel hat also nichts zu zählen. Mein Worker behielt fünfzehn Minuten lang das eine Replica, mit dem er gestartet war; das Plattform-Log meldete "no triggers defined".
- Eine Queue-Regel übergibt das Zählen an KEDA. Alle 30 Sekunden fragt KEDA die Queue nach der Zahl wartender Nachrichten und teilt durch die Einstellung Queue Length: ein Ziel pro Replica, kein Schwellenwert. 200 Nachrichten ÷ 10 = 20 Replicas, begrenzt auf das Maximum von 10.
- Die Identität der Regel braucht eine Rolle. Die Scale-Regel meldet sich mit der Managed Identity der App an, aber eine Identität ist nur ein Ausweis. Ohne Datenrolle auf dem Storage Account kann der Scaler nicht zählen, und die App zeigt keinen Fehler. Mit Storage Queue Data Contributor skalierte sie von 1 auf 10.
- Jede Nachricht weckt die App; eine leere Queue lässt sie gehen. Drei Nachrichten bei null Replicas weckten nach 41 Sekunden ein Replica. Nachdem die Queue leer war, blieben alle zehn Replicas noch fünf Minuten und waren dann innerhalb von 40 Sekunden weg.
Niemand zählt
Ein Queue-Worker hat keinen Ingress: keinen öffentlichen HTTP-Endpunkt, niemand ruft ihn auf, er holt sich seine Arbeit aus der Queue. So habe ich meinen zuerst angelegt: kein Ingress, Minimum null, Maximum zehn, keine Scale-Regel.
Container Apps skaliert über Regeln. Die Standardregel zählt HTTP-Requests, und ein Worker ohne Ingress bekommt keine. Also beobachtete niemand die Queue: Die App behielt fünfzehn Minuten lang das eine Replica, mit dem sie gestartet war, während 200 Nachrichten warteten. Weder hoch auf zehn noch runter auf null. Die Doku warnt, dass so eine App auf null skalieren und nie wieder starten kann; meine hat sich einfach nie verändert. So oder so: Die Queue bewegt die Zahl nicht.
Dieses eine Replica hat auch keine einzige Nachricht verarbeitet. Das führt zum zweiten Problem weiter unten.
Die Queue-Regel
Mit einer Scale-Regel sagen Sie Container Apps, was es beobachten soll. Darunter läuft KEDA, ein Open-Source-Autoscaler. Bei einer Queue-Regel fragt KEDA alle 30 Sekunden die Zahl der wartenden Nachrichten ab und rechnet desiredReplicas = ceil(Nachrichten ÷ queueLength), zwischen Ihrem Minimum und Maximum. Stellen Sie sich eine Poststelle bei Nacht vor: Die Schreibtische sind die Replicas, das Postfach ist die Queue, und KEDA ist der Inspektor, der die Briefe zählt.
Die Regel, die ich hinzugefügt habe, mit der eigenen systemzugewiesenen Managed Identity der App (ohne Connection String):
az containerapp update -n queue-worker -g rg-demo \--scale-rule-name queue-scaling \--scale-rule-type azure-queue \--scale-rule-metadata accountName=mystorage \queueName=orders queueLength=10 \--scale-rule-identity system
Dasselbe im Template, so wie Container Apps es gespeichert hat:
scale:minReplicas: 0maxReplicas: 10rules:- name: queue-scalingazureQueue:accountName: mystoragequeueName: ordersqueueLength: 10identity: system
Der Befehl aus der Doku schlug bei mir fehl. Azure CLI 2.88.0 antwortete mit unrecognized arguments: --scale-rule-identity system: Dieses Flag kommt aus der CLI-Erweiterung containerapp (az extension add -n containerapp), die noch im Preview ist. Mit der Erweiterung (1.3.0b5) ging die Regel durch.
Ausweis und Schlüssel
Mit Regel und aktiver Identität sahen die nächsten vier Minuten genauso aus wie die ersten fünfzehn: ein Replica, 200 Nachrichten, kein Fehler an der App.
Die Scale-Regel authentifiziert sich mit der Identität der App. Die Identität ist der Ausweis, eine Rolle ist der Schlüssel. Ohne Rolle auf dem Storage Account bleibt die Tür zu: KEDA kann die Länge der Queue nicht lesen und skaliert nichts. Der Worker hatte dasselbe Problem. Sein eigenes Log meldete alle zehn Sekunden:
error: HttpResponseError: This request is not authorized to perform this operation using this permission.
Die Lösung war eine einzige Rollenzuweisung für die Identität der App auf dem Storage Account:
principal=$(az containerapp show -n queue-worker -g rg-demo --query identity.principalId -o tsv)storageId=$(az storage account show -n mystorage -g rg-demo --query id -o tsv)az role assignment create --assignee-object-id $principal \--assignee-principal-type ServicePrincipal \--role "Storage Queue Data Contributor" --scope $storageId
Storage Queue Data Contributor erlaubt dem Worker, Nachrichten zu lesen und zu löschen, und ließ den Scaler sie zählen. 93 Sekunden nach der Rollenzuweisung war die erste Nachricht weg, 13 Sekunden später liefen zehn Replicas.
Zehn Replicas, dann keins
| Ein Replica | Zehn Replicas (mein Durchlauf) | |
|---|---|---|
| 200 Nachrichten × 5 s Arbeit | etwa 17 Minuten | etwa 2 Minuten nach der ersten Nachricht |
| Nachrichten pro Replica | 200 | 19 bis 26 |
Die Queue war 223 Sekunden nach der Rollenzuweisung leer. Alle zehn Replicas blieben noch fünf Minuten: KEDA wartet nach einer leeren Queue fünf Minuten, bevor es auf Ihr Minimum herunterskaliert, hier null. Dann waren sie innerhalb von 40 Sekunden weg: 10 → 9 → 6 → 3 → 0.
Der letzte Test: bei null Replicas drei Nachrichten, die Queue Length weiterhin zehn pro Replica. 41 Sekunden später startete ein Replica, 25 Sekunden danach waren die drei Nachrichten erledigt. Die Queue Length legt fest, wie viele Nachrichten ein Replica übernehmen soll, nicht wann das erste startet. Die Standard-Aktivierungsschwelle von KEDA für die Queue ist null: Jede Nachricht weckt die App.
Wo der eigentliche Fehler steckte
Die App selbst zeigte nichts: läuft, kein Fehler. Der Live-Stream des System-Logs (az containerapp logs show --type system) meldete nur:
unable to get external metric azure-queue-orders for queue-worker: … encountered error
Kein Wort über Berechtigungen. Den vollständigen Eintrag hatte der Log-Analytics-Workspace hinter der Container-Apps-Umgebung, in der Tabelle ContainerAppSystemLogs_CL:
KEDAScalerFailed: GET https://mystorage.queue.core.windows.net/ordersRESPONSE 403: 403 This request is not authorized to perform this operation using this permission.ERROR CODE: AuthorizationPermissionMismatch
Wenn ein Queue-Worker nicht skaliert: Fragen Sie die System-Logs in Log Analytics ab und prüfen Sie zuerst die Rolle.
Was passierte, als ich es ausprobiert habe
Getestet am 20. Oktober 2026 in meinem eigenen Azure-Abonnement (westeurope, Azure CLI 2.88.0, containerapp-Erweiterung 1.3.0b5); danach wurde alles gelöscht. Der Worker ist meine eigene Python-App (azure-storage-queue mit ManagedIdentityCredential): Sie holt eine Nachricht, arbeitet 5 Sekunden daran und löscht sie. qwatch.py, ebenfalls von mir, hat die Nachrichten gesendet und Replica-Zahl und Queue-Länge abgefragt. Das Anlegen der Umgebung dauerte 17,6 Minuten, der Cloud-Build 68 Sekunden, die App 41 Sekunden.
Der erste Versuch, ohne Ingress und ohne Regel:
> az containerapp show -n queue-worker -g rg-demo --query "{ingress:properties.configuration.ingress, scale:properties.template.scale}" -o json{"ingress": null,"scale": {"cooldownPeriod": 300,"maxReplicas": 10,"minReplicas": 0,"pollingInterval": 30,"rules": null}}
Weitere zehn Minuten davon (nach den ersten drei):
3 s replicas 1 queue 200302 s replicas 1 queue 200602 s replicas 1 queue 200summary: first replica: 3 s | peak: 1 replicas at 3 s | queue empty: no | 0 replicas: not reached
Nach der Rolle: das Hochskalieren, das Abarbeiten und das Herunterskalieren:
80 s replicas 1 queue 20093 s replicas 1 queue 199106 s replicas 10 queue 196223 s replicas 10 queue 0482 s replicas 10 queue 0494 s replicas 9 queue 0507 s replicas 6 queue 0520 s replicas 3 queue 0533 s replicas 0 queue 0
Drei Nachrichten bei null:
28 s replicas 0 queue 341 s replicas 1 queue 366 s replicas 1 queue 0
Mein Watcher fragte etwa alle 13 Sekunden ab, der Sprung von 1 auf 10 Replicas lag also irgendwo zwischen 93 und 106 Sekunden; die Doku beschreibt Scale-up-Schritte von 1, 4, 8, 16 pro Auswertung, die meine Abfragen nicht auflösen konnten. Noch ein Detail: Eine CPU-Regel mit Minimum null nahm die API an (az containerapp update zeigte die Regel in der Antwort mit leeren Metadaten, dieselbe Anzeige-Eigenheit wie bei der HTTP-Regel im vorigen Video); laut Doku können CPU- und Memory-Regeln nicht auf null skalieren, was dieser Durchlauf nicht weiter getestet hat.
Weitere Scaler im Modul
| Ereignisquelle | Typ der Scale-Regel | Metrik pro Replica | Hinweis |
|---|---|---|---|
| Azure Storage Queue | azure-queue | queueLength | Managed Identity oder Connection String |
| Azure Service Bus | azure-servicebus | messageCount | 50 Nachrichten ÷ 5 = 10 Replicas; Topics brauchen subscriptionName |
| Azure Event Hubs | azure-eventhub | unprocessedEventThreshold | mehr Replicas als Partitionen bringen nichts |
| Apache Kafka | kafka | lagThreshold | die Zahl der Partitionen begrenzt sinnvolle Replicas |
| Cron | cron | desiredReplicas in einem Zeitfenster | mit anderen Regeln gewinnt die höchste Zahl |





