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 denna handledning:
- 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 utforskar Docker-containerbygget 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 i flera lager.
Tips
Om du är intresserad av att publicera .NET-appen som en container utan behov av Docker eller Podman kan du läsa Containerize a .NET app with dotnet publish.
Obs
Den här självstudien är inte för ASP.NET Core-appar. Om du använder ASP.NET Core kan du läsa handledningen Lär dig hur du containeriserar en ASP.NET Core-applikation.
Förutsättningar
Installera följande krav:
-
.NET 8+ SDK.
Om du har installerat .NET använder du kommandotdotnet --info
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 handledningen 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 ungefär som i följande katalogstruktur:
📁 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. Nu ändrar du kataloger och navigerar till mappen App från terminalsessionen. Använd kommandot dotnet run
för att starta appen. Programmet körs och skriver 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.
Tips
Om du använder Visual Studio Code skriver du följande kommando från föregående terminalsession:
code .
Det här kommandot öppnar 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. Överväg följande exempelutdata:
dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C
Om du skickar ett tal på kommandoraden till appen begränsas antalet till det beloppet och avslutas sedan. Prova med dotnet run -- 5
att räkna till fem.
Viktig
Alla parametrar efter --
skickas inte till kommandot dotnet run
och skickas i stället till ditt program.
Publicera .NET-app
För att appen ska vara lämplig för att skapa en avbildning måste den kompileras. Kommandot dotnet publish
är mest passande för detta, eftersom det skapar och publicerar appen. En djupgående referens finns i dotnet build och dotnet publish kommandodokumentation.
dotnet publish -c Release
Tips
Om du är intresserad av att publicera .NET-appen som en container utan behov av Docker kan du läsa Containerize a .NET app with dotnet publish.
Kommandot dotnet publish
kompilerar appen till mappen publicera. Sökvägen till mappen publish från arbetsmappen ska vara ./App/bin/Release/<TFM>/publish/:
Från mappen App hämtar du en kataloglista över publiceringsmappen för att kontrollera att DotNet.Docker.dll filen har skapats.
dir .\bin\Release\net9.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net9.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 1/6/2025 10:11 AM 431 DotNet.Docker.deps.json
-a---- 1/6/2025 10:11 AM 6144 DotNet.Docker.dll
-a---- 1/6/2025 10:11 AM 145408 DotNet.Docker.exe
-a---- 1/6/2025 10:11 AM 11716 DotNet.Docker.pdb
-a---- 1/6/2025 10:11 AM 340 DotNet.Docker.runtimeconfig.json
dir .\bin\Release\net8.0\publish\
Directory: C:\Users\default\docker-working\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
Skapa Dockerfile
Filen Dockerfile används av kommandot docker build
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-konsolapplikationen.
FROM mcr.microsoft.com/dotnet/sdk:9.0@sha256:3fcf6f1e809c0553f9feb222369f58749af314af6f063f389cbd2f913b4ad556 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:9.0@sha256:b4bea3a52a0a77317fa93c5bbdb076623f81e3e2f201078d89914da71318b5d8
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Notis
ASP.NET Core runtime-avbildningen används avsiktligt här, även om mcr.microsoft.com/dotnet/runtime:9.0
-avbildningen kan användas i stället.
FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:6c4df091e4e531bb93bdbfe7e7f0998e7ced344f54426b7e874116a3dc3233ff
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Note
ASP.NET Core-körningsavbildningen används avsiktligt här, även om avbildningen mcr.microsoft.com/dotnet/runtime:8.0
kan användas i stället.
Viktig
Det är en god praxis att inkludera en säker hashalgoritm (SHA) efter en bildtagg i en Dockerfile. Detta säkerställer att avbildningen inte manipuleras och att bilden är densamma som den du förväntar dig. SHA är en unik identifierare för avbildningen. Mer information finns i Docker Docs: Hämta en avbild från digest.
Tips
Den här Dockerfile- använder flerstegsversioner, som optimerar avbildningens slutliga storlek genom att skikta 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. Det dotnet
segmentet är containerlagringsplatsen, medan sdk
- eller aspnet
-segmentet är containeravbildningsnamnet. Avbildningen är taggad med 9.0
, som används för versionshantering. Därför är mcr.microsoft.com/dotnet/aspnet:9.0
.NET 9.0-runtime. Se till att du hämtar den körningsversion som matchar den körningsversion som din SDK riktar sig mot. Till exempel använde appen som skapades i föregående avsnitt .NET 9.0 SDK och basavbildningen som anges i Dockerfile är taggad med 9.0.
Viktig
När du använder Windows-baserade containeravbildningar måste du ange avbildningstaggen utöver 9.0
, till exempel mcr.microsoft.com/dotnet/aspnet:9.0-nanoserver-1809
i stället för mcr.microsoft.com/dotnet/aspnet:9.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 filen Dockerfile. Arbetsmappens katalogstruktur bör se ut så här. Några av filerna och mapparna på djupare nivå utelämnas för att spara utrymme i artikeln:
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └───📂 Release
│ └───📂 net9.0
│ ├───📂 publish
│ │ ├─── DotNet.Docker.deps.json
│ │ ├─── DotNet.Docker.dll
│ │ ├─── DotNet.Docker.exe
│ │ ├─── DotNet.Docker.pdb
│ │ └─── DotNet.Docker.runtimeconfig.json
│ ├─── DotNet.Docker.deps.json
│ ├─── DotNet.Docker.dll
│ ├─── DotNet.Docker.exe
│ ├─── DotNet.Docker.pdb
│ └─── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
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. Det dotnet
segmentet är containerlagringsplatsen, medan sdk
- eller aspnet
-segmentet är containeravbildningsnamnet. Avbildningen är taggad med 8.0
, som används för versionshantering. Därför är mcr.microsoft.com/dotnet/aspnet:8.0
.NET 8.0 runtime-miljön. Se till att du hämtar runtime-versionen som matchar den runtime som din SDK riktar sig mot. 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.
Viktig
När du använder Windows-baserade containeravbildningar måste du ange avbildningstaggen utöver 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 filen Dockerfile. Arbetsmappens katalogstruktur bör se ut så här. Några av filerna och mapparna på djupare nivå utelämnas 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
└──...
Instruktionen ENTRYPOINT
anger dotnet
som värd för DotNet.Docker.dll
. Det är dock möjligt att i stället definiera ENTRYPOINT
som själva appens körbara fil och förlita sig på operativsystemet som appvärd:
ENTRYPOINT ["./DotNet.Docker"]
Detta gör att appen körs direkt, utan dotnet
, och förlitar sig i stället på appvärden och det underliggande operativsystemet. Mer information om hur du distribuerar plattformsoberoende binärfiler finns i Skapa en plattformsoberoende binär.
Kör följande kommando för att skapa containern från terminalen:
docker build -t counter-image -f Dockerfile .
Docker bearbetar varje rad i Dockerfile.
.
i kommandot docker build
anger 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 motbild som pekar på avbildningen. När det här kommandot har slutförts kör du docker images
för att se en lista över installerade avbildningar:
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 1c1f1433e51d 32 seconds ago 223MB
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 217MB
Den counter-image
lagringsplatsen är namnet på avbildningen. Dessutom är bildtaggen, bildidentifieraren, storleken och när den skapades en del av utdata. 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:9.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
Kommandot FROM
anger basavbildningen och taggen som ska användas. Kommandot WORKDIR
ändrar den aktuella katalogen inuti containern till App.
Kommandot COPY
instruerar Docker att kopiera den angivna källkatalogen till en målmapp. I det här exemplet förs publiceringsinnehåll från till lagret build
och exporteras till mappen med namnet App/out, vilket utgör källan att kopiera från. Allt publicerat innehåll i katalogen App/out kopieras till den aktuella arbetskatalogen (App).
Nästa kommando, ENTRYPOINT
, instruerar Docker att konfigurera containern så att den körs som en körbar fil. När containern startar körs kommandot ENTRYPOINT
. När det här kommandot slutar stoppas containern automatiskt.
Tips
Innan .NET 8 kunde containrar som konfigurerades 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.
Not
.NET 6 standardiserar på prefixet DOTNET_
i stället för COMPlus_
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 COMPlus_
-prefixet 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 är stoppad.
docker create --name core-counter counter-image
Det här docker create
visar CONTAINER-ID för containern (din identifierare kommer att vara annorlunda):
d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
Om du vill se en lista över alla containrar använder du kommandot 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
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 kommandot docker start
för att starta containern och använder sedan kommandot docker ps
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
På samma sätt stoppar kommandot docker stop
containern. I följande exempel används kommandot docker stop
för att stoppa containern och använder sedan kommandot docker ps
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
Ansluta 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 tangenttryckningen Ctrl+C för att koppla från den körande containern. 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, koppla tillbaka så att du kan 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 sedan kommandot docker rm
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 kommandot docker run
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 kommandot Ctrl+C 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 kommandot docker run
kan du också ändra kommandot ENTRYPOINT
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 ändras ENTRYPOINT
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
Notat
Det här exemplet fungerar bara på Windows-containrar. Linux-containrar har inte cmd.exe
.
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 handledningen skapade du containrar och bilder. 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 eller REPOSITORY:TAG formaterad sträng.
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:9.0
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:8.0
Använd kommandot docker images
för att se en lista över installerade avbildningar.
Tips
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 basavbildningar med den körmiljön installerad när du planerar att skapa andra avbildningar baserade på den körmiljön.