Eine API braucht ein Sprachmodell. Packen Sie das Modell ins API-Image, bedeutet jedes Modell-Update einen neuen API-Build. Betreiben Sie es als eigenen Dienst, haben Sie einen Endpunkt mehr, den Sie absichern und skalieren müssen. Azure App Service bietet einen dritten Weg: Das Modell läuft direkt neben der API, in einem eigenen Container, auf demselben localhost.
Dieses Erklärvideo zeigt, was ein Sidecar in App Service ist, wie Sie den Hauptcontainer und seine Sidecars konfigurieren, wie die Container miteinander sprechen und Dateien teilen, wie Sie den fehlerhaften Container finden und wann ein eigener Dienst die bessere Wahl ist. Ein Bild hilft dabei: Eine Instanz der App ist eine Wohnung. Nur der Hauptcontainer hat die Haustür zur Straße, und jeder Sidecar ist ein Zimmer am Flur, dessen Zimmernummer sein Port ist.
Das Wichtigste
- Ein Hauptcontainer, bis zu neun Sidecars. Nur der Hauptcontainer erhält Traffic aus dem Internet, auf Port 80 oder 8080. Sidecars erreichen Sie von innen über
localhost:<port>. - Ein Lebenszyklus, ein Budget. Die Container starten, stoppen und skalieren gemeinsam und teilen sich CPU und Arbeitsspeicher des App Service Plans. Ein speicherhungriges Modell bremst die API daneben.
- Site Containers statt klassischer Einstellungen. Sidecar-Apps definieren je Container eine eigene Ressource;
WEBSITES_PORTund die EinstellungenDOCKER_REGISTRY_SERVER_*gelten nicht. Der Target Port ist nur eine Beschriftung. - localhost und
/home. Die Container rufen sich überlocalhostmit eindeutigen Ports auf und tauschen Dateien im gemeinsamen Ordner/homeaus. Behandeln Sie beides wie eine echte Abhängigkeit: Timeouts, Readiness, wiederherstellbare Dateien.
Eine App, mehrere Container
Ein Sidecar ist ein zusätzlicher Container, der neben dem Hauptcontainer in derselben App-Service-App läuft. Eine App hat genau einen Hauptcontainer und bis zu neun Sidecars.
- Traffic: Nur der Hauptcontainer erhält Traffic aus dem Internet. Die Sidecars erreichen Sie von innen, über localhost.
- Lebenszyklus: App Service betreibt die Container als eine App. Sie starten und stoppen gemeinsam. Skaliert die App hoch, bekommt jede neue Instanz den Hauptcontainer und alle seine Sidecars; skaliert sie herunter, geht das ganze Set.
- Images: Jeder Container behält sein eigenes Image. Ein neues Modell-Image geht also live, ohne das API-Image anzufassen.
Der Preis ist die Isolation. Alle Container einer Instanz teilen sich CPU und Arbeitsspeicher des App Service Plans. Ein Modell, das den Großteil des Speichers belegt, bremst die API, selbst wenn die API kaum etwas braucht. Außerdem teilen sie sich ein Netzwerk und eine Umgebung: Betreiben Sie nur Images, denen Sie vertrauen.
Im Portal bietet App Service auch fertige Sidecars an, etwa einen Redis-Cache oder ein Phi-Sprachmodell für lokale Inferenz.
Hauptcontainer und Sidecars konfigurieren
Sidecar-Apps haben ein eigenes Konfigurationsmodell, die Site Containers. Ein klassischer Custom Container ist ein einziger Wert (DOCKER| plus Image-Name); eine Sidecar-App hat stattdessen eine Ressource pro Container. Vor den Sidecars betrieb App Service mehrere Container mit Docker Compose; Docker Compose wird am 31. März 2027 eingestellt, Sidecars sind der Nachfolger.
Legen Sie die App mit der Option --sitecontainers-app an, oder konvertieren Sie eine bestehende Custom-Container-App. Klassische Einstellungen wie WEBSITES_PORT und DOCKER_REGISTRY_SERVER_* konfigurieren Site Containers nicht.
az webapp create -g rg -p plan -n chatapi \--sitecontainers-appaz webapp sitecontainers convert -g rg -n myapp \--mode sitecontainers
Jeder Container bekommt einen eindeutigen Namen, eine vollständige Image-Referenz und eine Rolle. Genau einer hat isMain auf true, und er muss auf Port 80 oder 8080 lauschen: Nur diese Ports nehmen Traffic von außen an. Jeder Sidecar bekommt eigenen Namen, eigenes Image und eigenen Port.
az webapp sitecontainers create -g rg -n chatapi \--container-name chat-api --is-main \--image myacr.azurecr.io/chat-api:v1 --target-port 8080az webapp sitecontainers create -g rg -n chatapi \--container-name model-server \--image myacr.azurecr.io/model-server:v1 \--target-port 11434
Der Target Port ist nur eine Beschriftung. Er leitet nichts weiter und ändert den Prozess nicht; das Image selbst muss auf diesem Port lauschen.
Einstellungen gibt es in zwei Geltungsbereichen. App-Einstellungen erreichen jeden Container. Container-Variablen gehören zu einem Container, und in einer Container-Definition ist der Wert der Variablen der Name einer App-Einstellung, nicht der Wert selbst. Eine Spec-Datei enthält das ganze Set als JSON, sodass ein einziger Befehl (--sitecontainers-spec-file) alle Container anlegt oder aktualisiert:
[ { "name": "chat-api", "properties": { … } },{ "name": "model-server", "properties": {"image": "myacr.azurecr.io/model-server:v1","targetPort": "11434", "isMain": false,"authType": "UserAssigned","userManagedIdentityClientId": "<client-id>","environmentVariables": [{ "name": "MODEL_NAME","value": "MODEL_NAME_VALUE" }] } } ]
Images ziehen: Beide Images können aus Azure Container Registry kommen. Mit einer User-assigned Managed Identity nennt jeder Container den Auth-Typ und die Client-ID der Identität, und diese Identität braucht die Rolle AcrPull. Verwenden Sie einen festen Tag statt latest: Ein wandernder Tag kann nach dem nächsten Neustart ein anderes Image bedeuten. Prüfen Sie danach mit az webapp sitecontainers list, was angekommen ist: jeder Container mit Rolle, Port und Image.
Localhost und ein gemeinsamer Ordner
Alle Container einer Instanz teilen sich einen Network Namespace. Die API ruft das Modell also über http://localhost:11434 auf: nicht über einen Container-Namen, nicht über einen Service-Namen. Deshalb muss auch jeder Port eindeutig sein; zwei Prozesse können nicht auf demselben Port lauschen. Skalieren Sie auf drei Instanzen, ruft jede API das Modell auf ihrer eigenen Instanz auf. Die Adresse ändert sich nie.
Lokal heißt nicht zuverlässig. Das Modell kann neu starten, keinen Speicher mehr haben oder schlicht zu lange brauchen. Behandeln Sie den Aufruf wie jeden Remote-Aufruf: ein kurzer Timeout für den Verbindungsaufbau, eine Deadline für die ganze Anfrage und Wiederholungen nur, wenn der Aufruf gefahrlos wiederholt werden kann.
MODEL = "http://localhost:11434/v1/chat/completions"timeout = httpx.Timeout(10.0, connect=2.0)async with httpx.AsyncClient(timeout=timeout) as client:async with asyncio.timeout(30):r = await client.post(MODEL, json=body)
Readiness: Die API kann lange vor dem Modell bereit sein. Geben Sie der API einen Readiness-Check, der zuerst das Modell fragt und mit 503 antwortet, bis das Modell bereit ist. Richten Sie die Warm-up-Anfragen von App Service mit WEBSITE_WARMUP_PATH auf diesen Pfad und akzeptieren Sie mit WEBSITE_WARMUP_STATUSES nur eine 200; dann wartet der Traffic, bis das Modell bereit ist.
@app.get("/health/ready")def ready():try:r = requests.get(MODEL_HEALTH, timeout=5)r.raise_for_status()return {"status": "ready"}, 200except requests.RequestException:return {"status": "not ready"}, 503
WEBSITE_WARMUP_PATH=/health/readyWEBSITE_WARMUP_STATUSES=200
Dateien: App Service bindet denselben Ordner /home in jeden Container ein. Der Model-Server schreibt ein Manifest nach /home/models, und die API liest genau denselben Pfad; zusätzliche Volume Mounts sind nicht nötig. Schreiben Sie zuerst unter einem temporären Namen und benennen Sie die Datei dann um, damit der Leser nie eine halb geschriebene Datei sieht:
shared = Path("/home/models")tmp = shared / "manifest.json.tmp"tmp.write_text(json.dumps(info))tmp.replace(shared / "manifest.json")
Zwei Regeln halten das funktionsfähig: Setzen Sie WEBSITES_ENABLE_APP_SERVICE_STORAGE nicht auf false, das entfernt den gemeinsamen Ordner, und behandeln Sie diese Dateien als wiederherstellbar. Daten, die bleiben müssen, gehören in Azure Storage oder in eine Datenbank.
Wenn etwas ausfällt
Ein Sidecar-Fehler zeigt sich meist als Fehler in der Haupt-App. Arbeiten Sie sich von außen nach innen vor, eine Grenze nach der anderen, und ändern Sie immer nur eine Sache:
- Definitionen.
az webapp sitecontainers listzeigt einen fehlenden Sidecar, einen falschen Tag oder zwei Hauptcontainer;showgibt eine vollständige Definition aus, undstatussagt, ob der Container läuft. - Image ziehen. Ein Pull scheitert, bevor Ihr Code läuft. Prüfen Sie Image-Name und Tag, die Identität und ihre Rolle
AcrPull. Eine frische Rollenzuweisung kann ein paar Minuten dauern; warten Sie, bevor Sie auf Passwörter umsteigen. Die Registry muss außerdem Azure-Resource-Manager-Tokens akzeptieren (die Voreinstellung); ist das abgeschaltet, scheitern Pulls mit „token validation failed". - Start.
az webapp sitecontainers log --container-name model-serverzeigt nur die Ausgabe dieses Containers. Achten Sie auf einen Exit-Code, eine fehlende Variable, einen falschen Port oder einen Prozess, der sich beendet, statt im Vordergrund zu bleiben. - Arbeitsspeicher. Neustarts ohne Fehlermeldung bedeuten oft, dass dem Modell der Speicher ausging. Ein Modell zu laden braucht viel Speicher, und jedes Hochskalieren lädt es auf der neuen Instanz erneut. Vergleichen Sie die CPU- und Speichermetriken mit dem Zeitpunkt des Fehlers.
- Der localhost-Aufruf. Sein Fehler zeigt, wo Sie suchen müssen:
| Fehler | Bedeutung |
|---|---|
| Connection refused | auf dem Port lauscht nichts |
| Timeout | das Modell ist langsam, lädt noch oder hat keine Ressourcen mehr |
| HTTP-Fehler | die Verbindung stand: Prüfen Sie die Anfrage oder den Model-Server |
Sidecar oder eigener Dienst?
| Ein Sidecar passt, wenn | Ein eigener Dienst ist besser, wenn |
|---|---|
| jede Instanz genau einen lokalen Helfer braucht | mehrere Apps sich das Modell teilen |
| er mit der App startet, stoppt und skaliert | er eine GPU oder eigene Skalierung braucht |
| Beispiele: ein kleines Modell für eine API, ein Telemetrie-Collector, ein lokaler Cache | er eine eigene Sicherheitsgrenze braucht oder laufen muss, während die App neu startet |
Messen Sie, bevor Sie entscheiden: wie viel Speicher das Modell zum Laden braucht, was beide Container zusammen unter echter Last verbrauchen und den Spitzenwert, wenn bei einem Deployment oder beim Hochskalieren Container gleichzeitig starten. Wählen Sie einen Plan für diese gemeinsame Spitze plus Reserve. Belegt das Modell den Großteil der Instanz oder braucht es eine andere Skalierung, ziehen Sie es aus: Das kostet einen Netzwerk-Hop, aber die API kämpft nicht mehr mit dem Modell um Speicher.



