Azure Container Apps für .NET: Wann ACA statt App Service oder AKS?

10 Minuten Florian Bader
Azure Container Apps geben .NET-Teams einen pragmatischen Mittelweg zwischen einfachem PaaS und vollem Kubernetes-Betrieb.

Azure Container Apps geben .NET-Teams einen pragmatischen Mittelweg zwischen einfachem Platform as a Service (PaaS) und vollem Kubernetes-Betrieb. Genau diese belastbare Mitte fehlt oft, sobald Dockerfiles, Worker Services oder queue-basierte Last ins Spiel kommen. Für solche Container-Szenarien stößt App Service schneller an Grenzen. Azure Kubernetes Service (AKS) löst fast alles, bringt aber auch Aufwand für Clusterbetrieb, Upgrades, Policies und Plattform-Standards mit.

Genau in diese Lücke passen Azure Container Apps (ACA). Für Teams, die Container bewusst einsetzen wollen, aber keinen eigenen Kubernetes-Betrieb brauchen, ist ACA oft ein pragmatischer Weg. In diesem Artikel schauen wir uns an, wann das für Web APIs, Background Worker und kleinere Service-Setups sinnvoll ist und wann du besser bei App Service bleibst oder direkt zu AKS gehst.

Das eigentliche Entscheidungsproblem

App Service bleibt für viele Business-Anwendungen ein sehr starker Default. Wenn du eine klassische ASP.NET-Core-Web-App oder eine Web API mit überschaubarer Last betreibst, kommst du schnell produktiv und hast wenig Plattformaufwand. Wenn du tiefer in dieses Betriebsmodell einsteigen willst, schau in unseren Artikel: Azure App Services - Skalierung & Kostenoptimierung.

Die Grenzen zeigen sich meist nicht beim ersten Deployment, sondern beim zweiten oder dritten Schritt. Du willst vielleicht einen separaten Worker neben deiner API betreiben, Releases kontrolliert per Revision ausrollen oder auf Queue-Last statt nur auf HTTP reagieren. An diesem Punkt merkst du, dass du eigentlich keine klassische Webhosting-Plattform mehr suchst, sondern eine Container-Plattform.

AKS ist dann die andere Seite des Spektrums. Mit Azure Kubernetes Service bekommst du maximale Kontrolle über Cluster, Networking, Policies und Kubernetes-Erweiterungen. Du bekommst aber auch maximale Verantwortung, vom Node-Pool-Design bis zur Betriebsreife deiner Plattform.

ACA sitzt sauber dazwischen. Du arbeitest von Anfang an mit Containern, bekommst automatische Skalierung, Revisions und Jobs, musst aber keinen eigenen Kubernetes-Unterbau betreiben. Die Leitfrage lautet deshalb eher: Brauchst du echte Kubernetes-Funktionen oder reicht dir eine verwaltete Container-Plattform?

PlattformOperationsSkalierungDeployment-ModellGeeignet für
App Servicegeringstark für HTTP, weniger flexibel für EventsApp oder einzelner Container, Slotsklassische Web Apps und APIs
Azure Container AppsmittelHTTP, Queue, Events, scale to zeroContainer Apps, Revisions, JobsAPIs, Worker, kleinere Service-Setups
AKShochsehr flexibel, volle Kubernetes-WeltDeployments, Helm, Operators, GitOpsPlattformen mit echtem Kubernetes-Bedarf

Azure Container Apps in 5 Minuten

Für .NET-Teams reichen ein paar Kernbegriffe, um ACA sinnvoll einzuordnen. Ein Container App Environment ist die gemeinsame Laufzeitumgebung für mehrere Apps. Darin betreibst du einzelne Container Apps, zum Beispiel eine öffentliche Checkout-API, einen internen Import-Worker und einen geplanten Abrechnungsjob.

Spannend wird ACA durch das Revisionsmodell. Jedes neue Deployment kann als neue Revision parallel zur bisherigen Version bereitstehen. Über Revisions und Traffic Splitting kannst du selbst kontrollieren, wie viel Traffic auf die neue Version geht. Das ist besonders praktisch, wenn du neue Versionen zuerst smoke-testen willst, bevor sie den vollen Traffic bekommen. Und wenn etwas schiefgeht, kannst du die Revision einfach zurückdrehen.

Für den Alltag wichtig sind außerdem Ingress, Scale Rules und Workload Profiles. Ingress entscheidet, ob deine App extern oder nur intern erreichbar ist. Scale Rules legen fest, wann ACA zusätzliche Replikate startet oder wieder herunterfährt. Sie können auf HTTP, TCP oder Event-Quellen basieren, was für .NET-Worker mit Service Bus oder Storage Queue direkt relevant ist. Mit Workload Profiles entscheidest du, ob das serverless geprägte Consumption-Modell reicht oder ob du dedizierte Profile für mehr Kontrolle und Isolation brauchst.

Wichtig ist auch, was ACA nicht von dir verlangt. Du musst keine Kubernetes-Nodes patchen, keine Cluster-Upgrades planen und keine Basisplattform für jeden Workload selbst betreiben. Du konzentrierst dich auf Container, Skalierung und Deployments, während Azure den Kubernetes-Unterbau verwaltet. Und wenn deine Background Jobs gar keinen Dauer-Worker brauchen, sind ACA Jobs oft die sauberere Wahl.

Aber auch Function Apps können direkt in ACA laufen. Wenn du bereits eine Azure Function App hast, kannst du sie in einen Container packen und in ACA betreiben. Das ist besonders praktisch, wenn du die Function App in eine bestehende ACA-Umgebung einbinden willst, die bereits Revisions, Traffic Splitting und Jobs nutzt.

Der pragmatische Deploy-Pfad für .NET

Der einfachste Einstieg beginnt nicht mit einer komplexen Plattformarchitektur, sondern mit einem einzelnen sauberen Container. Eine ASP.NET-Core-Web-API oder ein Worker Service reicht völlig aus, um ACA sinnvoll kennenzulernen. Für den Build kannst du ein klassisches Multi-Stage-Dockerfile nutzen oder direkt .NET SDK Container Publish verwenden, wenn du die Toolchain bewusst schlank halten willst.

Ein solides Dockerfile für eine API sieht zum Beispiel so aus. Es ist kurz, reproduzierbar und setzt den Port passend für ACA auf 8080.

# Build-Stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

COPY . .
RUN dotnet restore src/Checkout.Api/Checkout.Api.csproj

# App host ist für ACA nicht nötig
RUN dotnet publish src/Checkout.Api/Checkout.Api.csproj \
    -c Release \
    -o /app/publish \
    /p:UseAppHost=false

# Runtime-Stage
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app

COPY --from=build /app/publish .
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080

ENTRYPOINT ["dotnet", "Checkout.Api.dll"]

Danach folgt der Standardpfad, den viele Teams ohnehin schon aus anderen Azure-Setups kennen. Deine Pipeline baut das Image, pusht es in Azure Container Registry (ACR) und deployed die neue Version nach ACA. Spätestens hier solltest du die Sicherheitsgrundlagen mitdenken, also Identity statt Secrets, klare Konfigurationstrennung und Infrastructure as Code (IaC) statt Portal-Klicks.

Für den Plattformteil reicht anfangs ein kleines Bicep-Setup. Das folgende Beispiel zeigt eine öffentliche API mit User-assigned Managed Identity, ACR-Anbindung, Health Probes und einfacher HTTP-Skalierung. Es geht davon aus, dass die ACA-Umgebung bereits existiert.

param location string = resourceGroup().location
param acrName string = 'acrlunarisprod'

resource userIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'id-checkout-api-prod'
  location: location
}

resource acaEnvironment 'Microsoft.App/managedEnvironments@2024-03-01' existing = {
  name: 'aca-env-prod'
}

resource app 'Microsoft.App/containerApps@2024-03-01' = {
  name: 'checkout-api-prod'
  location: location
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${userIdentity.id}': {}
    }
  }
  properties: {
    managedEnvironmentId: acaEnvironment.id
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        traffic: [
          {
            latestRevision: true
            weight: 100
          }
        ]
      }
      registries: [
        {
          server: '${acrName}.azurecr.io'
          identity: userIdentity.id
        }
      ]
    }
    template: {
      containers: [
        {
          name: 'api'
          image: '${acrName}.azurecr.io/checkout-api:2026.05.31'
          resources: {
            cpu: json('0.5')
            memory: '1Gi'
          }
          probes: [
            {
              type: 'Liveness'
              httpGet: {
                path: '/health/live'
                port: 8080
              }
            }
            {
              type: 'Readiness'
              httpGet: {
                path: '/health/ready'
                port: 8080
              }
            }
          ]
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 5
        rules: [
          {
            name: 'http'
            http: {
              concurrentRequests: 50
            }
          }
        ]
      }
    }
  }
}

Die Identity aus dem Beispiel braucht auf der Registry zusätzlich die Rolle AcrPull, sonst wird die App zwar angelegt, kann das Image aber nicht ziehen. Die Rollenzuweisung sieht in Bicep zum Beispiel so aus.

var acrPullRoleDefinitionId = subscriptionResourceId(
  'Microsoft.Authorization/roleDefinitions',
  '7f951dda-4ed3-4680-a7ca-43fe172d538d'
)

resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' existing = {
  name: acrName
}

resource acrPullAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(acr.id, userIdentity.id, acrPullRoleDefinitionId)
  scope: acr
  properties: {
    roleDefinitionId: acrPullRoleDefinitionId
    principalId: userIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

Für den Zugriff auf Key Vault, Storage oder SQL solltest du keine Secrets in die App ziehen, wenn Azure Identity das schon für dich lösen kann. Wenn du tiefer in dieses Sicherheitsmodell einsteigen willst, schau in unseren Artikel: Managed Identity in Azure: Auth ohne Secrets.

Skalierung, Releases und Betrieb

Genau hier spielt ACA seine Stärken aus. Eine öffentliche API kann auf HTTP skalieren, ein Worker auf Queue-Länge und ein geplanter Prozess wird als Job nur dann ausgeführt, wenn er wirklich gebraucht wird. Für unregelmäßige Last ist Scale to Zero attraktiv, spart Kosten, bringt aber Cold Starts mit. Für latenzkritische öffentliche APIs ist minReplicas: 1 oft die bessere Entscheidung.

Auch das Revisionsmodell ist im Alltag mehr wert, als es aussieht. Wenn du eine neue Version deiner API ausrollst, kannst du sie zunächst mit einem kleinen Traffic-Anteil live schalten, Smoke- bzw. UI-Tests darauf laufen lassen und bei Problemen schnell zurückdrehen. Das ersetzt keine saubere Release-Disziplin, reduziert aber den operativen Aufwand deutlich.

Ein kontrollierter Rollout lässt sich schon mit wenigen Azure-CLI-Befehlen umsetzen.

# Mehrere Revisionen aktiv lassen
az containerapp revision set-mode \
  --name checkout-api-prod \
  --resource-group rg-lunaris-prod \
  --mode multiple

# Bestehende Revision behält 90 Prozent, neue bekommt 10 Prozent
az containerapp ingress traffic set \
  --name checkout-api-prod \
  --resource-group rg-lunaris-prod \
  --revision-weight checkout-api-prod--blue=90 checkout-api-prod--green=10

Die Revisionsnamen im Beispiel sind Platzhalter. In der Praxis liest du sie per az containerapp revision list aus oder arbeitest mit Revision Labels, damit dein Rollout-Skript stabil bleibt.

Für Background Processing lohnt sich ein Blick auf ACA Jobs. Ein Dauer-Worker ist nicht automatisch die beste Lösung. Wenn dein Rechnungsversand alle 15 Minuten läuft oder dein CSV-Import nur nachts startet, sind ACA Jobs oft günstiger und sauberer als ein Service, der rund um die Uhr untätig mitläuft.

Betrieb verschwindet durch ACA nicht, er verschiebt sich nur auf eine angenehmere Ebene. Du brauchst weiterhin Log Analytics und Monitoring, sinnvolle Alerts, klare Ressourcenlimits und ein Mindestmaß an Lasttests. Der Unterschied zu AKS ist nicht, dass es keine Ops mehr gibt, sondern dass du dich stärker auf Workloads und weniger auf Clustermechanik konzentrieren kannst.

Wo ACA stark ist und wo App Service oder AKS besser passen

ACA ist besonders stark für containerisierte Web APIs, interne Services, ereignisgetriebene Worker und kleinere Microservice-Setups. Ein typisches Beispiel ist ein Team mit einer öffentlichen Bestell-API, einem Service-Bus-Worker für Auftragsverarbeitung und einem nächtlichen Exportjob für das ERP-System. Das alles lässt sich auf ACA sauber bündeln, ohne dass du gleich eine eigene Kubernetes-Plattform aufbauen musst.

Ein großer Pluspunkt ist auch das Freikontingent von ACA. Für kleine APIs oder Worker, die nicht dauerhaft laufen oder moderate Ressourcen benötigen, zahlt man praktisch nichts oder deutlich weniger als bei anderen Plattformen.

Bei App Service solltest du bleiben, wenn Container für dein Team aktuell keinen echten Mehrwert liefern. Eine einzelne ASP.NET-Core-Anwendung mit stabiler Last, klassischem Deployment und Wunsch nach maximalem PaaS-Komfort ist dort oft besser aufgehoben. Gerade wenn das Team wenig Betriebszeit investieren kann oder will, ist Einfachheit ein echter Architekturvorteil und kein Rückschritt.

Zu AKS solltest du greifen, wenn die Anforderungen bewusst nach Kubernetes riechen. ACA deckt internes Ingress, VNet-Integration und mehrere Workloads pro Umgebung zwar gut ab. Sobald du aber eigene Ingress Controller, DaemonSets, Operators oder einen Plattformansatz für mehrere Teams mit standardisiertem Cluster-Betrieb brauchst, ist AKS die passendere Wahl.

Du solltest auch die Grenzen von ACA ehrlich einplanen. Prüfe Quotas und Plattformlimits früh und behandle Stateful oder sehr spezialisierte Workloads mit Vorsicht. ACA ersetzt also nicht pauschal App Service oder AKS, sondern schließt eine sehr nützliche Lücke zwischen beiden.

Ein schlanker Produktions-Startpunkt

Für einen guten Start brauchst du keine riesige Zielarchitektur, aber ein paar Standards sollten vom ersten Tag an stehen. Lege eine eigene ACA-Umgebung pro Umgebung oder klar abgegrenztem Workload-Bereich an, binde ACR sauber an, aktiviere Managed Identity, schalte Log Analytics ein und entscheide bewusst, welche Apps extern erreichbar sein sollen. Health Probes, minReplicas, maxReplicas und Ressourcenlimits gehören nicht in die zweite Ausbaustufe, sondern in das erste brauchbare Setup.

Ebenso wichtig ist die Disziplin rund um Namensgebung und IaC. Wenn du das früh sauber setzt, vermeidest du unnötige Umbauten in der heißen Phase. Für die Azure-Seite hilft dir unser Artikel: Digitale Sternschnuppen: Azure Naming Conventions. Für den breiteren Betriebsblick lohnt sich außerdem: Azure Well-Architected Framework.

Definiere außerdem Exit-Kriterien. Wenn Container in deinem Projekt keinen echten Nutzen bringen, ist ein Rückweg zu App Service legitim. Wenn dagegen Security-, Networking- oder Plattformanforderungen deutlich wachsen und ein Plattformteam bereitsteht, kann der nächste logische Schritt AKS sein.

Die pragmatische Entscheidung für dein nächstes .NET-Hosting

App Service bleibt der einfachste Weg. AKS bleibt der mächtigste Weg. Azure Container Apps sind für viele .NET-Teams der beste Mittelweg, wenn Container helfen, Kubernetes aber keinen direkten Business-Nutzen bringt.

Wenn du neue Services planst oder bestehende Workloads überprüfst, dann baue die Plattform nicht größer als nötig. Frage zuerst nach Betriebsaufwand, Skalierungsmodell, Release-Sicherheit und Teamfähigkeit, und entscheide erst dann über das Produkt. Welche eurer .NET-Workloads wären eigentlich ACA-Kandidaten? Schau gerne bei uns auf LinkedIn vorbei und diskutiere mit.

Autoren

Florian Bader

Florian Bader

Florian ist Solution Architect und Microsoft Most Valuable Professional (MVP) für Azure IoT und DevOps mit langjähriger Erfahrung im Bereich DevOps, Cloud und Digitalisierung. Er unterstützt Unternehmen dabei, effiziente und effektive Lösungen zu entwickeln, die ihre digitalen Projekte nachhaltig zum Erfolg führen.