Procedura per pubblicare un'API .NET su Azure Container Apps partendo da un progetto vuoto. L'immagine viene costruita da Azure, quindi sul computer non serve Docker, e l'applicazione scarica l'immagine dal registro con un'identità gestita, senza chiavi.

Occorre: un account Azure con una sottoscrizione attiva, .NET 10 e l'interfaccia a riga di comando di Azure sul computer, un browser. Durata: circa quaranta minuti, quasi tutti di attesa per la creazione dell'ambiente. Costo: il registro Basic costa 0,17 USD al giorno; l'applicazione si paga a consumo, con 0,56 USD per milione di richieste, e con le repliche minime a zero non consuma quando nessuno la chiama.

Il portale delle schermate è in inglese: i nomi dei comandi sono riportati come appaiono a schermo.

Preparare l'applicazione

1. Crea il progetto

dotnet new webapi -n api-demo
cd api-demo

Il modello crea un'API con un solo endpoint, /weatherforecast. Non serve modificarla.

2. Provala in locale

dotnet run --launch-profile http

Apri http://localhost:5291/weatherforecast: risponde con cinque previsioni in JSON. Ferma l'applicazione con Ctrl+C.

3. Scrivi il Dockerfile

Nella cartella del progetto, accanto a api-demo.csproj:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY api-demo.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app .
EXPOSE 8080
ENTRYPOINT ["dotnet", "api-demo.dll"]

Serve anche un .dockerignore, altrimenti le cartelle compilate in locale finiscono nell'immagine e la compilazione dentro il contenitore fallisce:

bin/
obj/

L'immagine aspnet:10.0 ascolta sulla porta 8080: è il numero da ripetere nel passo 9.

Costruire l'immagine su Azure

4. Crea il registro

Su portal.azure.com, cerca Container registries e premi + Create. Sotto Resource group premi Create new e scrivi il nome: il gruppo si crea qui, non prima.

Campo Valore
Resource group rg-guide-ca-01 (nuovo)
Registry name acrguideca01
Location West Europe
Pricing plan Basic

Il nome del registro deve essere unico in tutta Azure e ammette solo lettere e numeri. Premi Review + create e poi Create.

Creazione del registro con il gruppo di risorse nuovo

5. Costruisci l'immagine

Dalla cartella del progetto:

az login
az acr build --registry acrguideca01 --image api-demo:1.0 .

Il comando carica la cartella su Azure, costruisce l'immagine là e la lascia nel registro: sul computer Docker non serve. Nella prova la costruzione è durata 49 secondi.

6. Controlla l'immagine

Nel registro apri Repositories e premi api-demo. La scheda riporta l'etichetta 1.0 e l'impronta dell'immagine.

Il deposito api-demo con l'etichetta 1.0

Creare l'applicazione

7. Dati di base

Cerca Container Apps, premi + Create e compila la prima scheda.

Campo Valore
Resource group rg-guide-ca-01
Container app name ca-demo-01
Deployment source Container image
Region West Europe

L'ambiente viene proposto nuovo, con un nome generato: va bene così.

Scheda Basics della creazione dell'applicazione

8. Scegli l'immagine

Passa a Container e indica l'immagine appena costruita.

Campo Valore
Image source Azure Container Registry
Registry acrguideca01.azurecr.io
Image api-demo
Image tag 1.0
Authentication type Managed identity
Managed identity System assigned identity (environment)

Con l'identità gestita non ci sono chiavi da copiare: il portale assegna da sé il ruolo ACR pull sul registro, come scrive sotto il campo.

Scheda Container con immagine e identità gestita

9. Apri la porta

Passa a Ingress e attiva la casella Ingress.

Campo Valore
Ingress traffic Accepting traffic from anywhere
Ingress type HTTP
Target port 8080

Target port è la porta su cui ascolta il contenitore, non quella da cui si entra: fuori si entra sempre in HTTPS sulla 443. Se il numero non coincide con quello del contenitore, l'applicazione si crea lo stesso ma l'indirizzo non risponde.

Scheda Ingress con la porta 8080

10. Crea e attendi

Premi Review + create e poi Create. Vengono creati quattro oggetti: il registro era già lì, qui si aggiungono l'ambiente, l'area di lavoro per i log e l'applicazione. Nella prova sono serviti circa quindici minuti, quasi tutti per l'ambiente.

A fine creazione apri la risorsa: in Essentials ci sono lo stato Running e l'indirizzo pubblico.

Pagina dell'applicazione con indirizzo e stato Running

Provare

11. Chiama l'API

Apri l'indirizzo dell'applicazione aggiungendo /weatherforecast. Risponde lo stesso JSON della prova in locale.

Risposta dell'API nel browser

12. Scalatura e log

In App → Scale si vede la regola creata in automatico: Min replicas a 0, Max replicas a 10 e una regola http-scaler. Con il minimo a zero, dopo cinque minuti senza richieste l'applicazione si spegne e la richiesta successiva la riaccende.

Regole di scalatura con minimo a zero

In Monitoring → Log stream si legge l'avvio del contenitore:

Now listening on: http://[::]:8080
Hosting environment: Production
Content root path: /app
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.

L'avviso compare perché il modello di progetto chiama UseHttpsRedirection e dentro il contenitore non c'è nessuna porta HTTPS: il traffico cifrato si ferma all'ingresso di Container Apps. Non blocca niente, l'API risponde lo stesso. Per non vederlo più, applica UseHttpsRedirection solo in sviluppo.

Flusso dei log con l'avvio del contenitore

Eliminare le risorse

13. Elimina il gruppo di risorse

Apri rg-guide-ca-01: contiene quattro risorse.

Le quattro risorse dentro il gruppo

Premi Delete resource group. Il pannello elenca le risorse e chiede di riscrivere il nome del gruppo.

Pannello di eliminazione con il nome riscritto

Premi Delete e conferma nella finestra che compare.

Richiesta di conferma definitiva

Finché il gruppo esiste, il registro continua a essere addebitato anche se l'applicazione è spenta.

Prezzi, nomi dei comandi e schermate rilevati sul portale di Azure il 4 novembre 2026, regione West Europe, con .NET 10.0.401 e l'interfaccia a riga di comando di Azure 2.91.0.