• English icon
  • German icon
Erklärvideo

Azure Container Apps erklärt: Umgebungen, Revisionen, Secrets

· Reihe: Container auf Azure

azureazure-container-appscontainersrevisionsdevops

Das Video ist auf Englisch.

Sie spielen ein neues Image in Azure Container Apps ein, und für einen Moment laufen zwei Versionen der App nebeneinander: Die alte bekommt jeden Request, bis die neue bereit ist. Dann rotieren Sie einen API-Schlüssel, und die App nutzt weiter den alten. Beides folgt aus derselben Idee, der Revision.

Dieses Erklärvideo geht ein komplettes Deployment durch: was eine Container-Apps-Umgebung ist, wie Sie mit der CLI und mit YAML deployen, wie Einstellungen und Secrets in den Container gelangen, wie er ohne Passwort aus einer privaten Registry zieht und wie Sie prüfen, ob ein Deployment wirklich funktioniert. Ein Bild hilft dabei: Die Umgebung ist eine Stadt, jede Container App eine U-Bahn-Linie und jede Revision ein Zug, einmal gebaut aus einem Image und einem Satz Einstellungen, danach nie mehr verändert.

Das Wichtigste

  • Die Umgebung ist die Grenze. Apps in einer Umgebung teilen ein virtuelles Netzwerk und standardmäßig einen Log-Analytics-Arbeitsbereich. Nutzen Sie getrennte Umgebungen für Entwicklung, Test und Produktion.
  • Jede Änderung am Template baut eine neue Revision. Im Single-Revision-Modus (Standard) behält die alte Revision den gesamten Traffic, bis die neue bereitgestellt, hochskaliert und durch ihre Health-Probes gekommen ist.
  • Secrets gehören zur App. Eine Secret-Änderung baut keine neue Revision; die laufenden Container behalten den Wert vom Start, bis die Revision neu startet.
  • Mit Managed Identity ziehen, von außen nach innen prüfen. AcrPull auf Azure Container Registry, kein Passwort; danach show, Logs, Revisionen und Replikate.

Die Umgebung

Eine Umgebung ist die Grenze, in der Ihre Container Apps leben. Apps in derselben Umgebung teilen ein virtuelles Netzwerk und schreiben ihre Logs an denselben Ort, standardmäßig in einen Log-Analytics-Arbeitsbereich. Damit ist sie das natürliche Zuhause für Dienste, die zusammengehören, etwa eine API und den Hintergrund-Worker, der sie versorgt. Sie trennt auch Stufen: Entwicklung, Test und Produktion bekommen je eine eigene Umgebung, damit eine defekte Test-Revision nie die Produktion berührt.

Innerhalb der Umgebung entscheidet jede App, wer sie erreichen darf:

IngressWer die App aufrufen kann
ExternAufrufer außerhalb der Umgebung (bei einer öffentlichen Umgebung das Internet) und Apps darin
Internnur andere Apps in derselben Umgebung; Aufrufer von außen bekommen einen 404

In beiden Fällen lauscht der Container auf seinem Target-Port, und Container Apps liefert ihn per HTTPS auf Port 443 aus.

az containerapp env create \
--name aca-env-demo \
--resource-group rg-aca-demo \
--location centralus

Neue Umgebungen nutzen standardmäßig Workload-Profile mit einem Consumption-Profil, das auf null skaliert: Sie zahlen für das, was Ihre Apps nutzen.

Deployen und aktualisieren

Das schnellste erste Deployment ist az containerapp up: Ein Befehl kann die Umgebung und alles drumherum anlegen, das Image deployen und die Adresse der App ausgeben. Gut für einen ersten Versuch. Für echte Umgebungen legen Sie die Umgebung zuerst an und deployen mit az containerapp create hinein: dasselbe Image, derselbe Port, derselbe Ingress, aber nichts wird hinter Ihrem Rücken angelegt.

az containerapp create -n ai-api -g rg-aca-demo \
--environment aca-env-demo \
--image mcr.microsoft.com/k8se/quickstart:latest \
--target-port 80 --ingress external

So oder so baut Container Apps die erste Revision: eine Momentaufnahme der App mit Image, Einstellungen und Skalierungsregeln. Eine Revision ändert sich nie. Version zwei entsteht als neue Revision neben der laufenden:

az containerapp update -n ai-api -g rg-aca-demo \
--image myregistry.azurecr.io/ai-api:v2 \
--revision-suffix v2

Single-Revision-Modus (Standard): Die alte Revision behält den gesamten Traffic, während die neue startet, hochskaliert und ihre Health-Probes besteht. Erst dann wechselt der Traffic, und die alte Revision wird heruntergefahren. Wird die neue Revision nie bereit, wechselt nichts, und die Nutzer bleiben auf der alten Version. Im Multiple-Revision-Modus entscheiden Sie selbst und können den Traffic aufteilen, zum Beispiel 90 % zu 10 %.

YAML im Team: Halten Sie die ganze App in einer YAML-Datei in der Versionsverwaltung und prüfen Sie Änderungen wie Code. Mit --yaml ist die Datei die ganze Wahrheit: Die CLI ignoriert jedes andere Flag in diesem Befehl.

properties:
configuration:
ingress: { external: true, targetPort: 8000 }
template:
containers:
- name: ai-api
image: myregistry.azurecr.io/ai-api:v2

Einstellungen und Secrets

Dasselbe Image soll in Test und Produktion laufen; was sich unterscheidet, ist die Konfiguration. Nicht sensible Einstellungen wie ein Log-Level oder ein Feature-Flag kommen in Umgebungsvariablen. --set-env-vars ergänzt oder ändert eine und lässt die übrigen stehen.

Sensible Werte wie ein API-Schlüssel werden Secrets. Ein Secret gehört zur App, nicht zu einer Revision, und wird verschlüsselt gespeichert. Eine Umgebungsvariable verweist mit secretref: und dem Namen des Secrets darauf, und der Name muss exakt passen, auch in der Groß- und Kleinschreibung:

az containerapp secret set -n ai-api -g rg-aca-demo \
--secrets embeddings-api-key=<value>
az containerapp update -n ai-api -g rg-aca-demo \
--set-env-vars \
EMBEDDINGS_API_KEY=secretref:embeddings-api-key

In YAML heißt es secretRef, und die Datei enthält nur den Namen, nie den Wert:

properties:
template:
containers:
- name: ai-api
env:
- name: LOG_LEVEL
value: info
- name: EMBEDDINGS_API_KEY
secretRef: embeddings-api-key

Der Code weiß von alledem nichts. Er liest einfach eine Umgebungsvariable:

import os
key = os.environ["EMBEDDINGS_API_KEY"]

Die zwei Teile einer Container App. Das ist die Idee hinter der Frage vom Anfang:

TeilEnthältEine Änderung …
Template (properties.template)Image, Umgebungsvariablen, Skalierungsregelnbaut eine neue Revision
Konfiguration (properties.configuration)Secrets, Ingress, Registries, Revisionsmodusgilt für alle Revisionen, baut keine

Wenn Sie also ein Secret aktualisieren, erscheint keine neue Revision. Die laufenden Container haben ihre Secrets beim Start gelesen und behalten den alten Wert. Um den neuen zu übernehmen, starten Sie die Revision neu oder deployen eine neue:

az containerapp revision restart -n ai-api \
-g rg-aca-demo --revision ai-api--v2

Liegt das Secret in Azure Key Vault, referenzieren Sie es stattdessen über eine Managed Identity. Verweisen Sie auf das Secret ohne Version, holt Container Apps eine neue Version innerhalb von 30 Minuten und startet die aktiven Revisionen neu, die es verwenden.

Aus einer privaten Registry ziehen

Produktions-Images liegen meist in einer privaten Registry wie Azure Container Registry, also braucht die App die Berechtigung zum Pull. Benutzername und Passwort funktionieren mit fast jeder Registry, sind aber ein weiteres Secret, das Sie in jeder App speichern und rotieren müssen. Mit Azure Container Registry ist eine Managed Identity der bessere Weg: Die App bekommt eine eigene Identität in Microsoft Entra ID, die Registry vertraut dieser Identität, und nirgends existiert ein Passwort.

az containerapp create -n ai-api -g rg-aca-demo \
--environment aca-env-demo \
--image myregistry.azurecr.io/ai-api:v1 \
--registry-server myregistry.azurecr.io \
--registry-identity system \
--ingress external --target-port 8000

Die CLI nutzt die Identität der App und weist, wo sie kann, die Rolle AcrPull auf der Registry zu. AcrPull ist das Minimum: Die Identität kann Images ziehen, aber nie pushen. Ziehen mehrere Apps aus derselben Registry, empfiehlt Microsoft eine benutzerseitig zugewiesene Identität: Sie existiert vor der App, und viele Apps können sie teilen.

Tags: Container Apps fragt die Registry bei jedem Containerstart nach dem Image. Wandert ein Tag wie latest, kann ein Neustart oder ein Scale-out unbemerkt anderen Code ausführen; geben Sie deshalb jedem Release einen eigenen Tag. Nach jeder Änderung an der Registry deployen Sie eine Revision und sehen zu, wie sie startet, bevor Sie ihr vertrauen.

Prüfen, ob es funktioniert

Ein Befehl ohne Fehler ist noch keine funktionierende App. Prüfen Sie von außen nach innen:

  1. Die App. az containerapp show liefert die Konfiguration. Fragen Sie den Ingress nach der Adresse ab, prüfen Sie, ob er extern ist, wenn Aufrufer von außen kommen sollen, und rufen Sie einen Health-Endpunkt auf.
  2. Konsolenlogs sind das, was Ihr Container schreibt: eine fehlende Variable, ein Absturz, ein falscher Port. Standardmäßig zeigt logs show die letzten 20 Zeilen eines Replikats der neuesten Revision; --follow streamt sie live.
  3. Systemlogs (--type system) schreibt die Plattform: Image-Pulls, Probes, Neustarts. Ist der Container nie gestartet, schauen Sie dort.
  4. Revisionen. revision list zeigt, welche Revisionen aktiv sind, und ihren Laufzustand: Running, Activating, Degraded oder Failed. Nach jedem Update sollte eine neue erscheinen.
  5. Replikate sind die laufenden Kopien einer Revision. Eine leere Liste ist nicht immer ein Absturz: Standardmäßig skaliert eine App zwischen null und zehn Replikaten, ohne Traffic hat sie also einfach keins. Der nächste Request startet eines und wartet darauf; stört dieser Kaltstart, setzen Sie die minimale Replikatzahl auf eins.
az containerapp show -n ai-api -g rg-aca-demo \
--query properties.configuration.ingress.fqdn
az containerapp logs show -n ai-api -g rg-aca-demo \
--follow --tail 30
az containerapp logs show -n ai-api -g rg-aca-demo \
--type system
az containerapp revision list -n ai-api -g rg-aca-demo
az containerapp replica list -n ai-api -g rg-aca-demo

Fünf schnelle Lösungen

SymptomLösung
Secret rotiert, nichts hat sich geändertdie Revision neu starten
Die App funktioniert von innen, nicht aus dem Internetihr Ingress ist intern
Die Revision wird nie bereitder Target-Port passt nicht zum Port, auf dem der Container lauscht
Ein Flag hatte keine WirkungSie haben auch eine YAML-Datei übergeben, und die Datei gewinnt
Derselbe Tag führt nach einem Neustart anderen Code ausjedem Release einen eigenen Tag geben

Weiterlesen

Video-Transkript (Englisch)

You ship a new image to Azure Container Apps. For a moment, two versions of your app run side by side, and the old one keeps every request, until the new one is ready. Then you rotate an API key, and your app keeps using the old one. Both come from the same idea. Once you see it, the rest of Container Apps makes sense.

In this video, you will see what a Container Apps environment is, how to deploy with the CLI and with YAML, how settings and secrets reach your container, how it pulls from a private registry without a password, and how to check that a deployment really works. Picture a city with a metro. The environment is the city. Every container app is a line. And every revision is a train: built once, from one image and one set of settings, and never changed.

So what is an environment? It's the boundary your container apps live in. Apps in the same environment share one virtual network, and they send their logs to the same place, by default one Log Analytics workspace. That makes it the natural home for services that belong together, like an API and the background worker that feeds it. It is also how you separate stages. Development, test and production each get their own environment, so a broken test revision never touches production. Inside the city, every app decides who may reach it. External ingress opens it to the outside: the internet, for a public environment. Internal ingress keeps it inside: only other apps in the same environment can call it. Either way, your container listens on its target port, and Container Apps serves it over HTTPS, on port 443. You can create the environment yourself, with az containerapp env create, a name, a resource group and a region. New environments use workload profiles by default, with a Consumption profile that scales to zero, and you pay for what your apps use.

Now the first deployment. The fastest way is az containerapp up. One command can create the environment and everything around it, deploy the image, and print the app's address. Great for a first try. For real environments, you usually create the environment first, and then deploy into it with az containerapp create. The same image, port and ingress, but nothing is created behind your back. Either way, Container Apps builds the first revision. A revision is a snapshot of your app: the image, its settings, its scale rules. And it never changes. So what happens when you ship version two? az containerapp update with the new image doesn't touch the running revision. It builds a new one, next to it. By default, an app runs in single revision mode. The old revision keeps all the traffic, while the new one starts, scales up, and passes its health probes. Only then does the traffic switch, and the old revision is shut down. If the new revision never gets ready, nothing switches. Your users stay on version one. In multiple revision mode, you decide yourself, and you can split the traffic, for example ninety percent to ten. Flags on the command line are fine for a test. For a team, keep the whole app in a YAML file, in source control, and review changes like code. With the yaml option, the file is the full truth: the CLI ignores every other flag on that command.

The same image should run in test and in production. What differs is configuration. Settings that aren't sensitive, like a log level or a feature flag, go into environment variables. Set env vars adds or changes one, and keeps the rest. Sensitive values, like an API key, become secrets. A secret belongs to the app, not to a revision, and it is stored encrypted. To use it, an environment variable points at it with secretref, followed by the secret's name. The name must match exactly, including its case. In YAML, it's secretRef. The file only holds the name, never the value. Your code doesn't know any of this. It just reads an environment variable. And here is the idea from the start. A container app has two parts. The template is the train: the image, the environment variables, the scale rules. Change anything in it, and you get a new revision. The configuration is the line: secrets, ingress, registries, the revision mode. Change it, and every revision sees the change, but no new revision is built. So you update a secret. No new revision appears. The running containers read their secrets when they started, so they keep the old value. To pick up the new one, restart the revision, or deploy a new one. If the secret lives in Azure Key Vault, reference it instead, through a managed identity. Point at the secret without a version, and Container Apps fetches a new version within thirty minutes, and restarts the active revisions that use it.

Production images usually live in a private registry, like Azure Container Registry. So the app needs permission to pull. The simple way is a username and a password. It works with almost any registry, but it's one more secret to store and rotate, in every app that pulls. With Azure Container Registry, there is a better way: a managed identity. The app gets its own identity in Microsoft Entra ID, and the registry trusts that identity. No password exists anywhere. On create, pass the registry server and registry identity system. The CLI uses the app's identity, and where it can, it assigns the AcrPull role on the registry for you. AcrPull is the least it needs: it can pull images, but never push them. When several apps pull from the same registry, Microsoft recommends a user-assigned identity: it exists before the app, and many apps can share it. One more detail. Container Apps checks the registry for the image every time a container starts. So if a tag like latest moves, a restart or a scale-out can quietly run different code. Use a unique tag for every release. And after any registry change, deploy a revision and watch it start, before you trust it.

The command finished without an error. Is the app actually working? Start with the app itself. az containerapp show returns its configuration. Query the ingress for the address, and check that it's external if you expect callers from outside. Then call a health endpoint. If the call fails, read the logs. Console logs are what your container writes: a missing variable, a crash, a wrong port. By default, logs show prints the last twenty lines, from one replica of the latest revision. Follow streams them live. System logs are what the platform writes: image pulls, probes, restarts. When the container never even started, look there. Next, the revisions. Revision list shows which revisions are active, and their running state: running, activating, degraded, or failed. After every update, a new one should appear. Finally, the replicas: the running copies of a revision. An empty list doesn't always mean a crash. By default, an app scales between zero and ten replicas, so with no traffic, it simply has none. The next request starts one, and has to wait for it. If that cold start hurts, set the minimum replicas to one.

Five mistakes that cost people hours. One: you rotated a secret, and nothing changed. Restart the revision. Two: the app works from the inside, but not from the internet. Its ingress is internal. Three: the revision never gets ready. The target port doesn't match the port your container listens on. Four: a flag you passed had no effect. You also passed a YAML file, and the file wins. Five: the same tag runs different code after a restart. Give every release its own tag.

To sum it up. The environment is the boundary: one network, one place for logs. Every change to the template builds a new revision, and traffic moves only when it's ready. Settings go into environment variables, sensitive values into secrets, and a changed secret needs a restart. A managed identity with AcrPull pulls your images without a password. And show, logs, revisions and replicas tell you whether it really works.

New image, new train. New secret, restart the train. If this was useful, subscribe for more practical .NET and Azure.

Brauchen Sie das in Ihrer eigenen Azure-Umgebung?

Ich entwickle, migriere und betreibe .NET-Plattformen auf Azure, mit Azure DevOps und Terraform. Wenn Ihr Team das sauber aufsetzen möchte, sehen Sie sich mein Angebot an.

Zu den Leistungen