A doua parte din seria despre Azure Container Apps. În prima parte am stabilit când merită migrarea. Aici trecem la practică: environment, deployment și scaling.
Container Apps environment
Un environment e granița în care rulează una sau mai multe container apps. Apps din același environment partajează aceeași rețea virtuală și pot comunica între ele prin service discovery intern. E și granița pentru observabilitate (Log Analytics) și pentru Dapr.
# Instaleaza extensia (o singura data)
az extension add --name containerapp --upgrade
# Inregistreaza provider-ii necesari
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
# Creeaza environment-ul
az containerapp env create \
--name my-aca-env \
--resource-group my-rg \
--location westeurope
Deployment-ul aplicației
Presupunem că ai deja o imagine în Azure Container Registry (construirea imaginii o acoperim în partea de CI/CD). Deployment-ul de bază:
az containerapp create \
--name my-api \
--resource-group my-rg \
--environment my-aca-env \
--image myregistry.azurecr.io/my-api:latest \
--target-port 8080 \
--ingress external \
--registry-server myregistry.azurecr.io \
--min-replicas 1 \
--max-replicas 10 \
--cpu 0.5 \
--memory 1.0Gi
Câteva detalii importante pentru o aplicație .NET:
- target-port — portul pe care ascultă Kestrel în container. Setează explicit
ASPNETCORE_URLS=http://+:8080în imagine sau ca variabilă de mediu. - ingress external — expune aplicația public. Folosește
internalpentru servicii care comunică doar în interiorul environment-ului. - min-replicas — setează 0 pentru scale-to-zero (revenim imediat).
Managed Identity pentru pull din ACR
În loc de credențiale de registry, folosește Managed Identity — consistent cu tot ce am construit în serie:
# Activeaza system-assigned identity pe container app
az containerapp identity assign \
--name my-api \
--resource-group my-rg \
--system-assigned
PRINCIPAL_ID=$(az containerapp identity show \
--name my-api --resource-group my-rg \
--query principalId -o tsv)
ACR_ID=$(az acr show --name myregistry --query id -o tsv)
# Rol AcrPull pentru identity
az role assignment create \
--assignee $PRINCIPAL_ID \
--role "AcrPull" \
--scope $ACR_ID
# Configureaza registry-ul sa foloseasca Managed Identity
az containerapp registry set \
--name my-api --resource-group my-rg \
--server myregistry.azurecr.io \
--identity system
Health probes
ACA folosește exact endpoint-urile de health checks pe care le-ai construit deja. Configurarea probelor liveness și readiness:
# containerapp.yaml (fragment din template)
properties:
template:
containers:
- name: my-api
image: myregistry.azurecr.io/my-api:latest
probes:
- type: Liveness
httpGet:
path: /health/live
port: 8080
periodSeconds: 10
failureThreshold: 3
- type: Readiness
httpGet:
path: /health/ready
port: 8080
periodSeconds: 5
failureThreshold: 3
- type: Startup
httpGet:
path: /health/live
port: 8080
periodSeconds: 5
failureThreshold: 30
Probe-ul Startup e util pentru aplicații .NET cu warm-up mai lung (JIT, încărcare Key Vault, conexiuni inițiale): ACA așteaptă până trece startup-ul înainte să înceapă liveness checks, evitând restart-uri premature.
Scaling rules cu KEDA
Aici e diferența majoră față de App Service. ACA folosește KEDA pentru scalare bazată pe evenimente, nu doar CPU/RAM.
Scale-to-zero
# min-replicas 0 = scale-to-zero cand nu e trafic
az containerapp update \
--name my-api --resource-group my-rg \
--min-replicas 0 \
--max-replicas 10
Cu min-replicas 0, aplicația se oprește complet când nu are trafic și pornește la prima cerere. Compromisul e cold start (câteva secunde pentru o aplicație .NET). Pentru API-uri cu trafic sporadic sau joburi ocazionale, economia de cost e semnificativă.
Scalare pe HTTP concurrency
# Scaleaza cand depaseste 50 request-uri concurente per replica
az containerapp update \
--name my-api --resource-group my-rg \
--scale-rule-name http-rule \
--scale-rule-type http \
--scale-rule-http-concurrency 50
Scalare pe coadă Service Bus
Scenariul clasic pentru care ACA e mai bun ca App Service: un worker care procesează mesaje și scalează în funcție de lungimea cozii.
# Scale rule pentru Service Bus queue
scale:
minReplicas: 0
maxReplicas: 20
rules:
- name: servicebus-rule
custom:
type: azure-servicebus
metadata:
queueName: orders
namespace: my-servicebus-namespace
messageCount: "10" # 1 replica per 10 mesaje in coada
identity: system # foloseste Managed Identity
Cu această regulă: 0 mesaje în coadă → 0 replici (cost zero). 100 de mesaje → 10 replici care le procesează în paralel. Coada se golește → scale back la 0. Exact tipul de elasticitate pe care App Service nu îl oferă nativ.
Observă identity: system: KEDA se autentifică la Service Bus prin Managed Identity, fără connection string — consistent cu principiile de securitate din serie.
Ce urmează
În partea a treia vedem cum activezi Dapr în Container Apps pentru comunicare între servicii: service invocation, pub/sub și state management — fără să scrii cod de infrastructură.
Întrebări? Scrie-mi la contact@ludoprogramming.com.