Formazione
Modulo
Creare un'applicazione Web per contenitori con Docker - Training
Usare Docker per compilare, archiviare e gestire immagini dei contenitori private con Registro Azure Container.
Questo browser non è più supportato.
Esegui l'aggiornamento a Microsoft Edge per sfruttare i vantaggi di funzionalità più recenti, aggiornamenti della sicurezza e supporto tecnico.
In questa esercitazione si apprenderà come inserire in contenitori un'applicazione .NET con Docker. I contenitori hanno molte funzionalità e vantaggi, ad esempio un'infrastruttura non modificabile, offrono un'architettura portabile e consentono la scalabilità. L'immagine può essere usata per creare contenitori per l'ambiente di sviluppo locale, il cloud privato o il cloud pubblico.
In questa esercitazione:
Si comprenderanno le attività di compilazione e distribuzione del contenitore Docker per un'applicazione .NET. La piattaforma Docker usa il motore Docker per compilare rapidamente app e inserirle in pacchetti come immagini Docker. Queste immagini vengono scritte nel formato Dockerfile per la distribuzione e l'esecuzione in un contenitore su più livelli.
Nota
Questa esercitazione non è destinata alle app core di ASP.NET. Se si usa ASP.NET Core, vedere l'esercitazione Informazioni su come inserire in contenitori un'applicazione ASP.NET Core.
Installare i prerequisiti seguenti:
dotnet --info
per determinare l'SDK in uso.dotnet --info
per determinare l'SDK in uso.È necessaria un'app .NET eseguita dal contenitore Docker. Aprire il terminale in uso, creare una cartella di lavoro se non è già stata creata e passare alla cartella. Nella cartella di lavoro eseguire il comando seguente per creare un nuovo progetto in una sottodirectory denominata App:
dotnet new console -o App -n DotNet.Docker
L'albero delle cartelle è simile al seguente:
📁 docker-working
└──📂 App
├──DotNet.Docker.csproj
├──Program.cs
└──📂 obj
├── DotNet.Docker.csproj.nuget.dgspec.json
├── DotNet.Docker.csproj.nuget.g.props
├── DotNet.Docker.csproj.nuget.g.targets
├── project.assets.json
└── project.nuget.cache
Il comando dotnet new
crea una nuova cartella denominata App e genera un'applicazione console "Hello World". Modificare le directory e passare alla cartella App dalla sessione del terminale. Usare il comando dotnet run
per avviare l'app. L'applicazione viene eseguita e stampa Hello World!
sotto il comando:
cd App
dotnet run
Hello World!
Il modello predefinito crea un'app che stampa sul terminale e quindi termina immediatamente. Per questa esercitazione si usa un'app che esegue un ciclo illimitato. Aprire il file Program.cs in un editor di testo.
Suggerimento
Se si usa Visual Studio Code, dalla sessione del terminale precedente digitare il comando seguente:
code .
Verrà aperta la cartella App che contiene il progetto in Visual Studio Code.
Il Program.cs dovrebbe essere simile al codice C# seguente:
Console.WriteLine("Hello World!");
Sostituirlo con il codice seguente che conta i numeri ogni secondo:
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
Salvare il file e testare di nuovo il programma con dotnet run
. Tenere presente che l'app viene eseguita per un tempo illimitato. Usare il comando di annullamento CTRL+C per arrestarla. Di seguito è riportato un esempio di output:
dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C
Se si passa un numero all'app nella riga di comando, verrà eseguito il conteggio fino a quel numero e quindi l'app verrà chiusa. Provare con dotnet run -- 5
per contare fino a cinque.
Importante
I parametri dopo --
non vengono passati al comando dotnet run
e vengono invece passati all'applicazione.
Prima di aggiungere l'app .NET all'immagine Docker, è necessario pubblicarla. È consigliabile che il contenitore esegua la versione pubblicata dell'app. Per pubblicare l'app, eseguire il comando seguente:
dotnet publish -c Release
Questo comando compila l'app nella cartella publish. Il percorso della cartella publish dalla cartella di lavoro deve essere .\App\bin\Release\net8.0\publish\
.
Questo comando compila l'app nella cartella publish. Il percorso della cartella publish dalla cartella di lavoro deve essere .\App\bin\Release\net7.0\publish\
.
Usare il comando ls
per ottenere un elenco di directory e verificare che il file DotNet.Docker.dll sia stato creato.
me@DESKTOP:/docker-working/app$ ls bin/Release/net8.0/publish
DotNet.Docker.deps.json DotNet.Docker.dll DotNet.Docker.exe DotNet.Docker.pdb DotNet.Docker.runtimeconfig.json
me@DESKTOP:/docker-working/app$ ls bin/Release/net7.0/publish
DotNet.Docker.deps.json DotNet.Docker.dll DotNet.Docker.exe DotNet.Docker.pdb DotNet.Docker.runtimeconfig.json
Il file Dockerfile viene usato dal comando docker build
per creare un'immagine del contenitore. Questo file è un file di testo denominato Dockerfile che non ha un'estensione.
Creare un file denominato Dockerfile nella directory contenente il file con estensione csproj e aprirlo in un editor di testo. Questa esercitazione usa l'immagine di runtime di ASP.NET Core (che contiene l'immagine di runtime .NET) e corrisponde all'applicazione console .NET.
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Nota
L'immagine di runtime di ASP.NET Core viene usata intenzionalmente qui, anche se l'immagine mcr.microsoft.com/dotnet/runtime:8.0
potrebbe essere stata usata.
Suggerimento
Questo Dockerfile usa compilazioni a più fasi, che ottimizzano le dimensioni finali dell'immagine tramite il layer della compilazione e lasciando solo gli artefatti necessari. Per altre informazioni, vedere Docker Docs: compilazioni a più fasi.
La parola chiave FROM
richiede un nome completo dell'immagine del contenitore Docker. Microsoft Container Registry (MCR, mcr.microsoft.com) è un syndicate dell'hub Docker, che ospita contenitori accessibili pubblicamente. Il segmento dotnet
è il repository di contenitori, mentre il segmento sdk
o aspnet
è il nome dell'immagine del contenitore. L'immagine è contrassegnata con 8.0
, che viene usata per il controllo delle versioni. Pertanto, mcr.microsoft.com/dotnet/aspnet:8.0
è il runtime di .NET 8.0. Assicurarsi di eseguire il pull della versione di runtime corrispondente al runtime di destinazione dell'SDK. Ad esempio, l'app creata nella sezione precedente usa .NET 8.0 SDK e l'immagine di base a cui si fa riferimento nel Dockerfile è contrassegnata con 8.0.
Importante
Quando si usano immagini contenitore basate su Windows, è necessario specificare il tag di immagine oltre semplicemente 8.0
, ad esempio, mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-1809
anziché mcr.microsoft.com/dotnet/aspnet:8.0
. Selezionare il nome dell'immagine in base all'utilizzo di Nano Server o Windows Server Core e alla versione del sistema operativo. È possibile trovare un elenco completo di tutti i tag supportati nella pagina dell'hub Docker di .NET.
Salvare il file Dockerfile. La struttura directory della cartella di lavoro deve avere un aspetto simile al seguente. Alcuni file e cartelle di livello più approfondito sono stati omessi per risparmiare spazio nell'articolo:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └──📂 Release
│ └──📂 net8.0
│ └──📂 publish
│ ├── DotNet.Docker.deps.json
│ ├── DotNet.Docker.exe
│ ├── DotNet.Docker.dll
│ ├── DotNet.Docker.pdb
│ └── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Nota
L'immagine di runtime ASP.NET Core viene usata intenzionalmente qui, anche se l'immagine mcr.microsoft.com/dotnet/runtime:7.0
potrebbe essere stata usata.
Suggerimento
Questo Dockerfile usa compilazioni a più fasi, che ottimizzano le dimensioni finali dell'immagine tramite il layer della compilazione e lasciando solo gli artefatti necessari. Per altre informazioni, vedere Docker Docs: compilazioni a più fasi.
La parola chiave FROM
richiede un nome completo dell'immagine del contenitore Docker. Il Registro Contenitori Microsoft (MCR, mcr.microsoft.com) è un syndicate dell'hub Docker, che ospita contenitori accessibili pubblicamente. Il segmento dotnet
è il repository di contenitori, mentre il segmento sdk
o aspnet
è il nome dell'immagine del contenitore. L'immagine è contrassegnata con 7.0
, che viene usata per il controllo delle versioni. Pertanto, mcr.microsoft.com/dotnet/aspnet:7.0
è il runtime di .NET 7.0. Assicurarsi di eseguire il pull della versione di runtime corrispondente al runtime di destinazione dell'SDK. Ad esempio, l'app creata nella sezione precedente ha usato .NET 7.0 SDK e l'immagine di base a cui si fa riferimento nel Dockerfile è contrassegnata con 7.0.
Salvare il file Dockerfile. La struttura directory della cartella di lavoro deve avere un aspetto simile al seguente. Alcuni file e cartelle di livello più approfondito sono stati omessi per risparmiare spazio nell'articolo:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └──📂 Release
│ └──📂 net7.0
│ └──📂 publish
│ ├── DotNet.Docker.deps.json
│ ├── DotNet.Docker.exe
│ ├── DotNet.Docker.dll
│ ├── DotNet.Docker.pdb
│ └── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
Dal terminale eseguire il comando seguente:
docker build -t counter-image -f Dockerfile .
Docker elaborerà ogni riga nel Dockerfile. .
nel comando docker build
imposta il contesto di compilazione dell'immagine. L'opzione -f
è il percorso del Dockerfile. Questo comando compila l'immagine e crea un repository locale denominato counter-image che punta a tale immagine. Dopo l'esecuzione del comando, eseguire docker images
per visualizzare un elenco delle immagini installate:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 217MB
Il repository counter-image
è il nome dell'immagine. Il tag latest
è il tag usato per identificare l'immagine. 2f15637dc1f6
è l'ID immagine. 10 minutes ago
è l'ora di creazione dell'immagine. 217MB
è la dimensione dell'immagine. I passaggi finali del Dockerfile sono creare un contenitore dall'immagine ed eseguire l'app, copiare l'app pubblicata nel contenitore e definire il punto di ingresso.
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 208MB
Il repository counter-image
è il nome dell'immagine. Il tag latest
è il tag usato per identificare l'immagine. 2f15637dc1f6
è l'ID immagine. 10 minutes ago
è l'ora di creazione dell'immagine. 208MB
è la dimensione dell'immagine. I passaggi finali del Dockerfile sono creare un contenitore dall'immagine ed eseguire l'app, copiare l'app pubblicata nel contenitore e definire il punto di ingresso.
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Il comando COPY
indica a Docker di copiare la cartella specificata nel computer in una cartella nel contenitore. In questo esempio, la cartella publish viene copiata in una cartella denominata app/out nel contenitore.
Il comando WORKDIR
modifica la directory corrente all'interno del contenitore in App.
Il comando successivo, ENTRYPOINT
, indica a Docker di configurare il contenitore in modo che venga eseguito come un eseguibile. All'avvio del contenitore viene eseguito il comando ENTRYPOINT
. Al termine del comando, il contenitore si arresta automaticamente.
Suggerimento
Prima di .NET 8, i contenitori configurati per l'esecuzione come di sola lettura potrebbero non riuscire con Failed to create CoreCLR, HRESULT: 0x8007000E
. Per risolvere questo problema, specificare una variabile di ambiente DOTNET_EnableDiagnostics
come 0
(subito prima del passaggio ENTRYPOINT
):
ENV DOTNET_EnableDiagnostics=0
Per altre informazioni sulle diverse variabili di ambiente .NET, vedere Variabili di ambiente .NET.
Nota
.NET 6 standardizza il prefisso DOTNET_
anziché COMPlus_
per le variabili di ambiente che configurano il comportamento di runtime di .NET. Tuttavia, il prefisso COMPlus_
continuerà a funzionare. Se si usa una versione precedente del runtime .NET, è comunque consigliabile usare il prefisso COMPlus_
per le variabili di ambiente.
Ora che si dispone di un'immagine che contiene l'app, è possibile creare un contenitore. Lo si può fare in due modi. Prima di tutto, creare un nuovo contenitore arrestato.
docker create --name core-counter counter-image
Questo comando docker create
crea un contenitore basato sull'immagine del contatore. L'output di questo comando mostra l'ID CONTENITORE (il contenitore sarà diverso) del contenitore creato:
d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
Per visualizzare un elenco di tutti i contenitori, usare il comando docker ps -a
:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0be06126f7d counter-image "dotnet DotNet.Docke…" 12 seconds ago Created core-counter
Il contenitore è stato creato con un nome specifico core-counter
, questo nome viene usato per gestire il contenitore. L'esempio seguente usa il comando docker start
per avviare il contenitore e quindi usa il comando docker ps
per visualizzare solo i contenitori in esecuzione:
docker start core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf01364df453 counter-image "dotnet DotNet.Docke…" 53 seconds ago Up 10 seconds core-counter
Analogamente, il comando docker stop
arresta il contenitore. L'esempio seguente usa il comando docker stop
per arrestare il contenitore e quindi usa il comando docker ps
per mostrare che non è in esecuzione alcun contenitore:
docker stop core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Quando un contenitore è in esecuzione, è possibile connettersi ad esso per visualizzare l'output. Usare i comandi docker start
e docker attach
per avviare il contenitore e osservare il flusso di output. In questo esempio viene usata la sequenza di tasti CTRL+C per disconnettersi dal contenitore in esecuzione. Questa sequenza di tasti termina il processo nel contenitore, a meno che non sia specificato diversamente, che arresta il contenitore. Il parametro --sig-proxy=false
garantisce che CTRL+C non arresti il processo nel contenitore.
Dopo essersi scollegati dal contenitore, collegarsi di nuovo per verificare che sia ancora in esecuzione e continui a eseguire il conteggio.
docker start core-counter
core-counter
docker attach --sig-proxy=false core-counter
Counter: 7
Counter: 8
Counter: 9
^C
docker attach --sig-proxy=false core-counter
Counter: 17
Counter: 18
Counter: 19
^C
Per questo articolo, non si vogliono contenitori che non fanno nulla. Eliminare il contenitore creato in precedenza. Se è in esecuzione, arrestarlo.
docker stop core-counter
L'esempio seguente elenca tutti i contenitori. Usare quindi il comando docker rm
per eliminare il contenitore e quindi controllare una seconda volta per eventuali contenitori in esecuzione.
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f6424a7ddce counter-image "dotnet DotNet.Dock…" 7 minutes ago Exited (143) 20 seconds ago core-counter
docker rm core-counter
core-counter
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Docker fornisce il comando docker run
per creare ed eseguire il contenitore con un unico comando. Questo comando elimina la necessità di eseguire docker create
e quindi docker start
. È anche possibile impostare il comando in modo che elimini automaticamente il contenitore quando viene arrestato. Ad esempio, usare docker run -it --rm
per eseguire due operazioni, ossia usare automaticamente il terminale corrente per connettersi al contenitore e quindi, al termine dell'esecuzione, rimuovere il contenitore:
docker run -it --rm counter-image
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C
Il contenitore passa anche i parametri all'esecuzione dell'app .NET. Per indicare all'app .NET di contarne solo tre, passare a 3.
docker run -it --rm counter-image 3
Counter: 1
Counter: 2
Counter: 3
Con docker run -it
, il comando CTRL+C arresta il processo in esecuzione nel contenitore, che a sua volta arresta il contenitore. Poiché è stato specificato il parametro --rm
, il contenitore viene eliminato automaticamente quando viene arrestato il processo. Verificare che non esista:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Il comando docker run
consente anche di modificare il comando ENTRYPOINT
dal Dockerfile e di eseguire qualcosa di diverso, ma solo per il contenitore in questione. Ad esempio, usare il comando seguente per eseguire bash
o cmd.exe
. Modificare il comando in base alle esigenze.
In questo esempio ENTRYPOINT
viene sostituito con bash
. Viene quindi eseguito il comando exit
che termina il processo e arresta il contenitore.
docker run -it --rm --entrypoint "bash" counter-image
root@9f8de8fbd4a8:/App# ls
DotNet.Docker DotNet.Docker.deps.json DotNet.Docker.dll DotNet.Docker.pdb DotNet.Docker.runtimeconfig.json
root@9f8de8fbd4a8:/App# dotnet DotNet.Docker.dll 7
Counter: 1
Counter: 2
Counter: 3
^C
root@9f8de8fbd4a8:/App# exit
exit
Docker include molti comandi diversi che creano, gestiscono e interagiscono con contenitori e immagini. I comandi Docker seguenti sono essenziali per la gestione dei contenitori:
Durante questa esercitazione sono stati creati contenitori e immagini. Se si preferisce, è possibile eliminare queste risorse. Usare i comandi seguenti per
Elencare tutti i contenitori
docker ps -a
Arrestare i contenitori in esecuzione in base al nome.
docker stop core-counter
Eliminare il contenitore
docker rm core-counter
Eliminare quindi le immagini che non si desidera conservare nel computer. Eliminare l'immagine creata dal Dockerfile e quindi eliminare l'immagine .NET su cui si basava il Dockerfile. È possibile usare l'IMAGE ID o la stringa formattata come REPOSITORY:TAG.
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:8.0
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:7.0
Usare il comando docker images
per visualizzare un elenco delle immagini installate.
Suggerimento
I file di immagine possono essere di grandi dimensioni. In genere è consigliabile rimuovere i contenitori temporanei creati durante il test e lo sviluppo dell'app. Conservare invece le immagini di base con il runtime installato se si prevede di compilare altre immagini basate su quel runtime.
Feedback su .NET
.NET è un progetto di open source. Selezionare un collegamento per fornire feedback:
Formazione
Modulo
Creare un'applicazione Web per contenitori con Docker - Training
Usare Docker per compilare, archiviare e gestire immagini dei contenitori private con Registro Azure Container.