Självstudie: Containerisera en .NET-app
I den här självstudien får du lära dig hur du containeriserar ett .NET-program med Docker. Containrar har många funktioner och fördelar, till exempel att vara en oföränderlig infrastruktur, tillhandahålla en bärbar arkitektur och möjliggöra skalbarhet. Avbildningen kan användas för att skapa containrar för din lokala utvecklingsmiljö, privata moln eller offentliga moln.
I den här kursen får du:
- Skapa och publicera en enkel .NET-app
- Skapa och konfigurera en Dockerfile för .NET
- Skapa en Docker-avbildning
- Skapa och köra en Docker-container
Du kommer att förstå hur Docker-containern skapar och distribuerar uppgifter för ett .NET-program. Docker-plattformen använder Docker-motorn för att snabbt skapa och paketera appar som Docker-avbildningar. Dessa avbildningar skrivs i Dockerfile-format som ska distribueras och köras i en container med flera lager.
Kommentar
Den här självstudien gäller inte för ASP.NET Core-appar. Om du använder ASP.NET Core läser du självstudien Lär dig hur du containeriserar en ASP.NET Core-program .
Förutsättningar
Installera följande krav:
- .NET 8+ SDK
Om du har .NET installerat använderdotnet --info
du kommandot för att avgöra vilken SDK du använder. - Docker Community Edition
- En tillfällig arbetsmapp för Dockerfile- och .NET-exempelappen. I den här självstudien används namnet docker-working som arbetsmapp.
- .NET 7+ SDK
Om du har .NET installerat använderdotnet --info
du kommandot för att avgöra vilken SDK du använder. - Docker Community Edition
- En tillfällig arbetsmapp för Dockerfile- och .NET-exempelappen. I den här självstudien används namnet docker-working som arbetsmapp.
Skapa .NET-app
Du behöver en .NET-app som Docker-containern kör. Öppna terminalen, skapa en arbetsmapp om du inte redan har gjort det och ange den. I arbetsmappen kör du följande kommando för att skapa ett nytt projekt i en underkatalog med namnet App:
dotnet new console -o App -n DotNet.Docker
Mappträdet ser ut så här:
📁 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
Kommandot dotnet new
skapar en ny mapp med namnet App och genererar ett "Hello World"-konsolprogram. Ändra kataloger och navigera till mappen App från terminalsessionen. dotnet run
Använd kommandot för att starta appen. Programmet körs och skrivs ut Hello World!
under kommandot:
cd App
dotnet run
Hello World!
Standardmallen skapar en app som skriver ut till terminalen och sedan omedelbart avslutas. I den här självstudien använder du en app som loopar på obestämd tid. Öppna filen Program.cs i en textredigerare.
Dricks
Om du använder Visual Studio Code skriver du följande kommando från föregående terminalsession:
code .
Då öppnas mappen App som innehåller projektet i Visual Studio Code.
Program.cs bör se ut som följande C#-kod:
Console.WriteLine("Hello World!");
Ersätt filen med följande kod som räknar tal varje sekund:
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));
}
Spara filen och testa programmet igen med dotnet run
. Kom ihåg att den här appen körs på obestämd tid. Använd kommandot Avbryt Ctrl+C för att stoppa det. Följande är ett exempel på utdata:
dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C
Om du skickar ett tal på kommandoraden till appen räknas det bara upp till det beloppet och avslutas sedan. Försök med dotnet run -- 5
för att räkna till fem.
Viktigt!
Eventuella parametrar efter --
skickas inte till dotnet run
kommandot och skickas i stället till ditt program.
Publicera .NET-app
Innan du lägger till .NET-appen i Docker-avbildningen måste den först publiceras. Det är bäst att låta containern köra den publicerade versionen av appen. Om du vill publicera appen kör du följande kommando:
dotnet publish -c Release
Det här kommandot kompilerar appen till publiceringsmappen. Sökvägen till publiceringsmappen från arbetsmappen ska vara .\App\bin\Release\net8.0\publish\
.
Det här kommandot kompilerar appen till publiceringsmappen. Sökvägen till publiceringsmappen från arbetsmappen ska vara .\App\bin\Release\net7.0\publish\
.
Från mappen App hämtar du en kataloglista över publiceringsmappen för att kontrollera att DotNet.Docker.dll filen skapades.
dir .\bin\Release\net8.0\publish\
Directory: C:\Users\default\App\bin\Release\net8.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/22/2023 9:17 AM 431 DotNet.Docker.deps.json
-a--- 9/22/2023 9:17 AM 6144 DotNet.Docker.dll
-a--- 9/22/2023 9:17 AM 157696 DotNet.Docker.exe
-a--- 9/22/2023 9:17 AM 11688 DotNet.Docker.pdb
-a--- 9/22/2023 9:17 AM 353 DotNet.Docker.runtimeconfig.json
dir .\bin\Release\net7.0\publish\
Directory: C:\Users\default\App\bin\Release\net7.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2/13/2023 1:52 PM 431 DotNet.Docker.deps.json
-a--- 2/13/2023 1:52 PM 6144 DotNet.Docker.dll
-a--- 2/13/2023 1:52 PM 153600 DotNet.Docker.exe
-a--- 2/13/2023 1:52 PM 11052 DotNet.Docker.pdb
-a--- 2/13/2023 1:52 PM 253 DotNet.Docker.runtimeconfig.json
Skapa Dockerfile
Dockerfile-filen används av docker build
kommandot för att skapa en containeravbildning. Den här filen är en textfil med namnet Dockerfile som inte har något tillägg.
Skapa en fil med namnet Dockerfile i katalogen som innehåller .csproj och öppna den i en textredigerare. I den här självstudien används ASP.NET Core-körningsavbildningen (som innehåller .NET-körningsavbildningen) och motsvarar .NET-konsolprogrammet.
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"]
Kommentar
ASP.NET Core-körningsavbildningen används avsiktligt här, även om avbildningen mcr.microsoft.com/dotnet/runtime:8.0
kunde ha använts.
Dricks
Den här Dockerfile använder flerstegsversioner, vilket optimerar avbildningens slutliga storlek genom att lagerföra bygget och endast lämna nödvändiga artefakter. Mer information finns i Docker Docs: flerstegsversioner.
Nyckelordet FROM
kräver ett fullständigt kvalificerat Docker-containeravbildningsnamn. Microsoft Container Registry (MCR, mcr.microsoft.com) är ett syndikat av Docker Hub, som är värd för offentligt tillgängliga containrar. Segmentet dotnet
är containerlagringsplatsen, medan sdk
eller-segmentet aspnet
är containeravbildningens namn. Bilden är taggad med 8.0
, som används för versionshantering. mcr.microsoft.com/dotnet/aspnet:8.0
Därför är .NET 8.0-körningen. Se till att du hämtar körningsversionen som matchar den körning som mål för din SDK. Till exempel använde appen som skapades i föregående avsnitt .NET 8.0 SDK och basavbildningen som refereras till i Dockerfile är taggad med 8.0.
Viktigt!
När du använder Windows-baserade containeravbildningar måste du ange avbildningstaggen utöver bara 8.0
, till exempel mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-1809
i stället för mcr.microsoft.com/dotnet/aspnet:8.0
. Välj ett avbildningsnamn baserat på om du använder Nano Server eller Windows Server Core och vilken version av operativsystemet. Du hittar en fullständig lista över alla taggar som stöds på . NET:s Docker Hub-sida.
Spara Dockerfile-filen. Arbetsmappens katalogstruktur bör se ut så här. Några av filerna och mapparna på djupare nivå har utelämnats för att spara utrymme i artikeln:
📁 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"]
Kommentar
ASP.NET Core-körningsavbildningen används avsiktligt här, även om avbildningen mcr.microsoft.com/dotnet/runtime:7.0
kunde ha använts.
Dricks
Den här Dockerfile använder flerstegsversioner, vilket optimerar avbildningens slutliga storlek genom att lagerföra bygget och endast lämna nödvändiga artefakter. Mer information finns i Docker Docs: flerstegsversioner.
Nyckelordet FROM
kräver ett fullständigt kvalificerat Docker-containeravbildningsnamn. Microsoft Container Registry (MCR, mcr.microsoft.com) är ett syndikat av Docker Hub – som är värd för offentligt tillgängliga containrar. Segmentet dotnet
är containerlagringsplatsen, medan sdk
eller-segmentet aspnet
är containeravbildningens namn. Bilden är taggad med 7.0
, som används för versionshantering. mcr.microsoft.com/dotnet/aspnet:7.0
Därför är .NET 7.0-körningen. Se till att du hämtar körningsversionen som matchar den körning som mål för din SDK. Till exempel använde appen som skapades i föregående avsnitt .NET 7.0 SDK och basavbildningen som refereras till i Dockerfile är taggad med 7.0.
Spara Dockerfile-filen. Arbetsmappens katalogstruktur bör se ut så här. Några av filerna och mapparna på djupare nivå har utelämnats för att spara utrymme i artikeln:
📁 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
└──...
Kör följande kommando från terminalen:
docker build -t counter-image -f Dockerfile .
Docker bearbetar varje rad i Dockerfile. I .
docker build
kommandot anges byggkontexten för avbildningen. Växeln -f
är sökvägen till Dockerfile. Det här kommandot skapar avbildningen och skapar en lokal lagringsplats med namnet counter-image som pekar på avbildningen. När det här kommandot är klart kör du docker images
för att se en lista över installerade avbildningar:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 217MB
Lagringsplatsen counter-image
är namnet på avbildningen. Taggen latest
är taggen som används för att identifiera avbildningen. 2f15637dc1f6
är avbildnings-ID:t. Är 10 minutes ago
den tid då avbildningen skapades. Är 217MB
storleken på bilden. De sista stegen i Dockerfile är att skapa en container från avbildningen och köra appen, kopiera den publicerade appen till containern och definiera startpunkten.
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
Lagringsplatsen counter-image
är namnet på avbildningen. Taggen latest
är taggen som används för att identifiera avbildningen. 2f15637dc1f6
är avbildnings-ID:t. Är 10 minutes ago
den tid då avbildningen skapades. Är 208MB
storleken på bilden. De sista stegen i Dockerfile är att skapa en container från avbildningen och köra appen, kopiera den publicerade appen till containern och definiera startpunkten.
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Kommandot COPY
instruerar Docker att kopiera den angivna mappen på datorn till en mapp i containern. I det här exemplet kopieras publiceringsmappen till en mapp med namnet App/out i containern.
Kommandot WORKDIR
ändrar den aktuella katalogen i containern till App.
Nästa kommando, ENTRYPOINT
, instruerar Docker att konfigurera containern så att den körs som en körbar fil. När containern startar ENTRYPOINT
körs kommandot. När det här kommandot avslutas stoppas containern automatiskt.
Dricks
Innan .NET 8 kan containrar som konfigurerats för att köras som skrivskyddade misslyckas med Failed to create CoreCLR, HRESULT: 0x8007000E
. Du kan åtgärda det här problemet genom att ange en DOTNET_EnableDiagnostics
miljövariabel som 0
(precis före ENTRYPOINT
steget):
ENV DOTNET_EnableDiagnostics=0
Mer information om olika .NET-miljövariabler finns i .NET-miljövariabler.
Kommentar
.NET 6 standardiserar på prefixet DOTNET_
i stället COMPlus_
för för miljövariabler som konfigurerar .NET-körningsbeteende. Prefixet COMPlus_
fortsätter dock att fungera. Om du använder en tidigare version av .NET-körningen bör du fortfarande använda prefixet COMPlus_
för miljövariabler.
Skapa en container
Nu när du har en avbildning som innehåller din app kan du skapa en container. Du kan skapa en container på två sätt. Skapa först en ny container som har stoppats.
docker create --name core-counter counter-image
Det här docker create
kommandot skapar en container baserat på motavbildningsavbildningen. Utdata från kommandot visar container-ID :t (ditt kommer att vara annorlunda) för den skapade containern:
d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
Om du vill se en lista över alla containrar använder du docker ps -a
kommandot:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0be06126f7d counter-image "dotnet DotNet.Docke…" 12 seconds ago Created core-counter
Hantera containern
Containern skapades med ett specifikt namn core-counter
, det här namnet används för att hantera containern. I följande exempel används docker start
kommandot för att starta containern och använder docker ps
sedan kommandot för att endast visa containrar som körs:
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
docker stop
På samma sätt stoppar kommandot containern. I följande exempel används docker stop
kommandot för att stoppa containern och använder docker ps
sedan kommandot för att visa att inga containrar körs:
docker stop core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Anslut till en container
När en container har körts kan du ansluta till den för att se utdata. Använd kommandona docker start
och docker attach
för att starta containern och titta på utdataströmmen. I det här exemplet används Ctrl+C-tangenttryckningen för att koppla från containern som körs. Den här tangenttryckningen avslutar processen i containern om inget annat anges, vilket skulle stoppa containern. Parametern --sig-proxy=false
ser till att Ctrl+C inte stoppar processen i containern.
När du har kopplat från containern kopplar du tillbaka för att kontrollera att den fortfarande körs och räknar.
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
Ta bort en container
I den här artikeln vill du inte att containrar ska hänga runt som inte gör något. Ta bort containern som du skapade tidigare. Om containern körs stoppar du den.
docker stop core-counter
I följande exempel visas alla containrar. Den använder docker rm
sedan kommandot för att ta bort containern och kontrollerar sedan en andra gång för alla containrar som körs.
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
Enkel körning
Docker tillhandahåller docker run
kommandot för att skapa och köra containern som ett enda kommando. Det här kommandot eliminerar behovet av att köra docker create
och sedan docker start
. Du kan också ange att det här kommandot ska ta bort containern automatiskt när containern stoppas. Använd till exempel docker run -it --rm
för att göra två saker, först automatiskt använda den aktuella terminalen för att ansluta till containern och sedan ta bort den när containern är klar:
docker run -it --rm counter-image
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C
Containern skickar också parametrar till körningen av .NET-appen. Om du vill instruera .NET-appen att bara räkna till tre skickar du in 3.
docker run -it --rm counter-image 3
Counter: 1
Counter: 2
Counter: 3
Med docker run -it
stoppar Ctrl+C-kommandot den process som körs i containern, vilket i sin tur stoppar containern. Eftersom parametern --rm
angavs tas containern bort automatiskt när processen stoppas. Kontrollera att den inte finns:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Ändra ENTRYPOINT
Med docker run
kommandot kan du också ändra ENTRYPOINT
kommandot från Dockerfile och köra något annat, men bara för containern. Använd till exempel följande kommando för att köra bash
eller cmd.exe
. Redigera kommandot efter behov.
I det här exemplet ENTRYPOINT
ändras till cmd.exe
. Ctrl+C trycks ned för att avsluta processen och stoppa containern.
docker run -it --rm --entrypoint "cmd.exe" counter-image
Microsoft Windows [Version 10.0.17763.379]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\>dir
Volume in drive C has no label.
Volume Serial Number is 3005-1E84
Directory of C:\
04/09/2019 08:46 AM <DIR> app
03/07/2019 10:25 AM 5,510 License.txt
04/02/2019 01:35 PM <DIR> Program Files
04/09/2019 01:06 PM <DIR> Users
04/02/2019 01:35 PM <DIR> Windows
1 File(s) 5,510 bytes
4 Dir(s) 21,246,517,248 bytes free
C:\>^C
Viktiga kommandon
Docker har många olika kommandon som skapar, hanterar och interagerar med containrar och avbildningar. Dessa Docker-kommandon är viktiga för att hantera dina containrar:
Rensa resurser
Under den här självstudien skapade du containrar och avbildningar. Ta bort dessa resurser om du vill. Använd följande kommandon för att
Visa en lista över alla containrar
docker ps -a
Stoppa containrar som körs med deras namn.
docker stop core-counter
Ta bort containern
docker rm core-counter
Ta sedan bort alla avbildningar som du inte längre vill ha på datorn. Ta bort avbildningen som skapades av Dockerfile och ta sedan bort .NET-avbildningen som Dockerfile baserades på. Du kan använda bild-ID:t eller den formaterade strängen 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
docker images
Använd kommandot för att se en lista över installerade avbildningar.
Dricks
Bildfiler kan vara stora. Vanligtvis tar du bort tillfälliga containrar som du skapade när du testade och utvecklade din app. Du brukar ha basavbildningarna med körningen installerad om du planerar att skapa andra avbildningar baserat på den körningen.