教學課程:將 .NET 應用程式

在本教學課程中,您將瞭解如何使用 Docker 將 .NET 應用程式。 容器有許多功能和優點,例如成為不可變的基礎結構、提供可攜的架構,以及啟用擴充性。 映像可用來為您的本機開發環境、私人雲端,或公用雲端建立容器。

在本教學課程中,您:

  • 建立和發行簡單的 .NET 應用程式
  • 建立和設定適用于 .NET 的 Dockerfile
  • 建置 Docker 映像
  • 建立及執行 Docker 容器

您將瞭解 .NET 應用程式的 Docker 容器組建和部署工作。 Docker 平臺會使用docker 引擎,快速建立應用程式並將其封裝為Docker 映射。 這些映像是以 Dockerfile 格式所撰寫,可在分層式容器中部署及執行。

注意

本教學課程不適用於 ASP.NET Core 應用程式。 如果您是使用 ASP.NET Core,請參閱瞭解如何將 ASP.NET Core 應用程式教學課程。

必要條件

安裝下列先決條件:

  • .NET SDK
    如果您已安裝 .NET,請使用 dotnet --info 命令來判斷您所使用的 SDK。
  • Docker 社區版本
  • Dockerfile和 .net 範例應用程式的暫存工作資料夾。 在本教學課程中,會使用 docker 工作 的名稱做為工作資料夾。

建立 .NET 應用程式

您需要 Docker 容器將執行的 .NET 應用程式。 開啟您的終端機,建立工作資料夾 (如果沒有),並進入該資料夾。 在工作資料夾中,執行下列命令,在名為 app的子目錄中建立新的專案:

dotnet new console -o App -n DotNet.Docker

您的資料夾樹狀目錄會如下所示:

📁 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

dotnet new 命令會建立名為App的新資料夾,並產生 "Hello World" 主控台應用程式。 從您的終端機會話,變更目錄並流覽至 應用程式 資料夾。 dotnet run使用命令來啟動應用程式。 應用程式將會執行,並在命令下方列印 Hello World!

dotnet run
Hello World!

預設範本會建立會列印到終端機,然後立即終止的應用程式。 針對此教學課程,您將使用無限期執行迴圈的應用程式。 在文字編輯器中開啟 Program.cs 檔案。

提示

如果您是使用 Visual Studio Code,請從先前的終端機會話中輸入下列命令:

code .

這會開啟 應用程式 資料夾,其中包含 Visual Studio Code 中的專案。

.Cs 看起來應該像下列 c # 程式 代碼:

Console.WriteLine("Hello World!");

使用下列每秒計算數字的程式碼來取代檔案:

var counter = 0;
var max = args.Length != 0 ? Convert.ToInt32(args[0]) : -1;
while (max == -1 || counter < max)
{
    Console.WriteLine($"Counter: {++counter}");
    await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}

儲存檔案,然後使用 dotnet run 再次測試程式。 請記住此應用程式會無限期執行。 使用 [取消] 命令 Ctrl + C 來停止。 以下是範例輸出:

dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C

如果您在命令列上傳遞一個數字給應用程式,它將只會計算到該數量,然後結束。 搭配 dotnet run -- 5 試用它以計算到五。

重要

-- 之後的任何參數都不會傳遞至 dotnet run 命令,而會改為傳遞至您的應用程式。

發佈 .NET 應用程式

將 .NET 應用程式新增至 Docker 映射之前,必須先發佈它。 最好讓容器執行應用程式的已發佈版本。 若要發佈應用程式,請執行下列命令:

dotnet publish -c Release

此命令會將您的應用程式編譯至 publish 資料夾。 從工作資料夾通往 publish 資料夾的路徑應該是 .\App\bin\Release\net6.0\publish\

應用程式 資料夾取得 [發佈] 資料夾的目錄清單,以確認已建立 DotNet.Docker.dll 檔案。

dir .\bin\Release\net6.0\publish\

    Directory: C:\Users\dapine\App\bin\Release\net6.0\publish

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---            3/8/2022 10:43 AM            431 DotNet.Docker.deps.json
-a---            3/8/2022 10:43 AM           6144 DotNet.Docker.dll
-a---            3/8/2022 10:43 AM         149504 DotNet.Docker.exe
-a---            3/8/2022 10:43 AM          10516 DotNet.Docker.pdb
-a---            3/8/2022 10:43 AM            253 DotNet.Docker.runtimeconfig.json

建立 Dockerfile

docker build 命令會使用 Dockerfile 檔案來建立容器映像。 這個檔案是名為 Dockerfile 的文字檔,不含副檔名。

在包含.csproj的目錄中建立名為Dockerfile的檔案,並在文字編輯器中開啟該檔案。 本教學課程將使用 ASP.NET Core 執行時間映射 (,其中包含 .net 執行時間映射) 並且對應于 .net 主控台應用程式。

FROM mcr.microsoft.com/dotnet/sdk:6.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:6.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]

注意

雖然可能已經使用了映射,但 mcr.microsoft.com/dotnet/runtime:6.0 在這裡刻意使用 ASP.NET Core 執行時間映射。

FROM關鍵字需要完整的 Docker 容器映射名稱。 Microsoft Container Registry (MCR,mcr.microsoft.com) 是 Docker Hub 的整合,可裝載可公開存取的容器。 dotnet區段是容器存放庫,而 sdkaspnet 區段則是容器映射名稱。 影像會標記 6.0 為,以用於版本控制。 因此, mcr.microsoft.com/dotnet/aspnet:6.0 是 .net 6.0 執行時間。 請確定您提取的執行階段版本符合您 SDK 的目標執行時間。 例如,在上一節中建立的應用程式使用 .NET 6.0 SDK,而且 Dockerfile 中所參考的基底映射會標記為 6.0

儲存 Dockerfile 檔案。 工作資料夾的目錄結構應如下所示。 有些較深層的檔案和資料夾已被省略,以節省文章中的空間:

📁 docker-working
    └──📂 App
        ├── Dockerfile
        ├── DotNet.Docker.csproj
        ├── Program.cs
        ├──📂 bin
        │   └──📂 Release
        │       └──📂 net6.0
        │           └──📂 publish
        │               ├── DotNet.Docker.deps.json
        │               ├── DotNet.Docker.exe
        │               ├── DotNet.Docker.dll
        │               ├── DotNet.Docker.pdb
        │               └── DotNet.Docker.runtimeconfig.json
        └──obj 📁
            └──...

從終端機執行下列命令:

docker build -t counter-image -f Dockerfile .

Docker 將會處理 Dockerfile 中的每一行。 命令中 docker build. 會設定影像的組建內容。 -f參數是Dockerfile的路徑。 此命令會建立映射,並建立名為 counter 的本機存放庫,指向該映射。 當此命令完成之後,執行 docker images 以查看已安裝的映像清單:

docker images
REPOSITORY                         TAG       IMAGE ID       CREATED          SIZE
counter-image                      latest    2f15637dc1f6   10 minutes ago   208MB

counter-image存放庫是映射的名稱。 latest標記是用來識別影像的標記。 2f15637dc1f6是映射識別碼。 10 minutes ago是建立映射的時間。 208MB是影像的大小。 Dockerfile的最後一個步驟是從映射建立容器並執行應用程式、將已發佈的應用程式複製到容器,以及定義進入點。

FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]

COPY 命令會指示 Docker,將您電腦上指定的資料夾複製到容器中的資料夾。 在此範例中,會將 publish 資料夾複製到容器中名為 app 的資料夾。

WORKDIR 命令會將容器內的 目前目錄 變更為 應用程式

下一個命令 ENTRYPOINT 會指示 Docker 將容器設定為以可執行檔的形式執行。 當容器啟動時,ENTRYPOINT 命令就會執行。 當此命令結束時,容器將會自動停止。

提示

為了增加安全性,您可以退出宣告診斷管線。 當您退出宣告此功能時,可讓容器以唯讀方式執行。 若要這樣做,請在步驟) 之前 ENTRYPOINT 將環境變數指定 DOTNET_EnableDiagnostics0 (:

ENV DOTNET_EnableDiagnostics=0

如需各種 .NET 環境變數的詳細資訊,請參閱 .net 環境變數

注意

.NET 6 會標準化前置 DOTNET_ 詞,而不是 COMPlus_ 設定 .net 執行時間行為的環境變數。 不過, COMPlus_ 前置詞將繼續運作。 如果您使用的是舊版的 .NET 執行時間,您仍然應該使用環境變數的 COMPlus_ 前置詞。

從終端機中執行 docker build -t counter-image -f Dockerfile .,並在該命令完成時,執行 docker images

docker build -t counter-image -f Dockerfile .
[+] Building 3.1s (14/14) FINISHED
 => [internal] load build definition from Dockerfile                              0.5s
 => => transferring dockerfile: 32B                                               0.0s
 => [internal] load .dockerignore                                                 0.6s
 => => transferring context: 2B                                                   0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:6.0              0.8s
 => [internal] load metadata for mcr.microsoft.com/dotnet/sdk:6.0                 1.1s
 => [stage-1 1/3] FROM mcr.microsoft.com/dotnet/aspnet:6.0@sha256:f1539d71        0.0s
 => [internal] load build context                                                 0.4s
 => => transferring context: 4.00kB                                               0.1s
 => [build-env 1/5] FROM mcr.microsoft.com/dotnet/sdk:6.0@sha256:16e355af1        0.0s
 => CACHED [stage-1 2/3] WORKDIR /App                                             0.0s
 => CACHED [build-env 2/5] WORKDIR /App                                           0.0s
 => CACHED [build-env 3/5] COPY . ./                                              0.0s
 => CACHED [build-env 4/5] RUN dotnet restore                                     0.0s
 => CACHED [build-env 5/5] RUN dotnet publish -c Release -o out                   0.0s
 => CACHED [stage-1 3/3] COPY --from=build-env /App/out .                         0.0s
 => exporting to image                                                            0.4s
 => => exporting layers                                                           0.0s
 => => writing image sha256:2f15637d                                              0.1s
 => => naming to docker.io/library/counter-image

docker images
REPOSITORY                         TAG       IMAGE ID       CREATED          SIZE
counter-image                      latest    2f15637dc1f6   10 minutes ago   208MB

Dockerfile 中的每個命令都會產生一個圖層,並建立映像識別碼。 (您的 映射識別碼 將會不同) 2f15637dc1f6 ,接下來您將根據此映射建立容器。

建立容器

您現在已有包含應用程式的映像,您可以建立一個容器。 您可以兩種方式建立容器。 首先,建立已停止的新容器。

docker create --name core-counter counter-image

docker create上述命令會根據計數器影像映射建立容器。 該命令的輸出會顯示 容器識別碼 (您的容器識別碼會是所建立容器的不同) :

cf01364df4539812684c64277f5363a8fb354ef4c90785dc0845769a6c5b0f8e

若要查看「所有」容器的清單,請使用 docker ps -a 命令:

docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS    PORTS     NAMES
cf01364df453   counter-image   "dotnet DotNet.Docke…"   18 seconds ago   Created             core-counter

管理容器

容器是使用特定名稱 core-counter 所建立,此名稱是用來管理容器。 下列範例會使用 docker start 命令來啟動容器,然後使用 docker ps 命令只顯示正在執行的容器:

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 命令將會停止容器。 下列範例會使用 docker stop 命令停止容器,然後使用 docker ps 命令顯示沒有任何容器正在執行:

docker stop core-counter
core-counter

docker ps
CONTAINER ID    IMAGE    COMMAND    CREATED    STATUS    PORTS    NAMES

連線到容器

當容器正在執行之後,您可以連線到它以查看輸出。 使用 docker startdocker attach 命令來啟動容器,並查看輸出資料流。 在此範例中,會使用 Ctrl + C 按鍵來卸離執行中的容器。 除非另有指定,否則此按鍵會結束容器中的進程,這會停止容器。 --sig-proxy=false參數可確保Ctrl + C不會停止容器中的進程。

當您從容器中斷連結之後,請重新連結以確認它仍在執行且正在進行計算。

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

刪除容器

在本文中,您不希望容器不會進行任何動作。 刪除您先前建立的容器。 如果容器正在執行,請停止它。

docker stop core-counter

下列範例會列出所有容器。 然後,它會使用 docker rm 命令來刪除容器,然後針對任何執行中的容器檢查第二次。

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 提供 docker run 命令來建立容器,並以單一命令執行。 使用此命令,就不需依序執行 docker createdocker start。 您也可以設定此命令,在容器停止時自動刪除容器。 例如,使用 docker run -it --rm 來執行兩個動作,首先,自動使用目前的終端機連線到容器,然後在容器完成時將其移除:

docker run -it --rm counter-image
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C

容器也會將參數傳遞至 .NET 應用程式的執行。 指示 .NET 應用程式只計算3次以上。

docker run -it --rm counter-image 3
Counter: 1
Counter: 2
Counter: 3

使用 docker run -it 時, Ctrl + C 命令會停止在容器中執行的進程,進而停止容器。 由於已提供 --rm 參數,因此會在程序停止時自動刪除容器。 確認它不存在:

docker ps -a
CONTAINER ID    IMAGE    COMMAND    CREATED    STATUS    PORTS    NAMES

變更 ENTRYPOINT

docker run 命令也可讓您從 Dockerfile 修改 ENTRYPOINT 命令並執行其他動作,但只適用於該容器。 例如,使用下列命令來執行 bashcmd.exe。 視需要編輯命令。

在此範例中,ENTRYPOINT 會變更為 cmd.exe。 按下Ctrl + C以結束進程並停止容器。

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

基本命令

Docker 有許多不同的命令,可建立、管理及與容器和映射互動。 這些 Docker 命令對於管理容器而言非常重要:

清除資源

在本教學課程中,您已建立容器和映射。 您可以視需要刪除這些資源。 使用下列命令

  1. 列出所有容器

    docker ps -a
    
  2. 停止依名稱執行的容器。

    docker stop counter-image
    
  3. 刪除容器

    docker rm counter-image
    

接下來,在電腦上刪除您不再需要的任何映像。 刪除您的 Dockerfile 所建立的映射,然後刪除 Dockerfile 所依據的 .net 映射。 您可以使用映像識別碼存放庫:標記格式的字串。

docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:6.0

使用 docker images 命令來查看已安裝的映像清單。

提示

映像檔可能很大。 一般而言,會移除您在測試及開發應用程式時所建立的暫存容器。 如果您打算根據已安裝的執行階段建置其他映像,您通常會使用該執行階段來保存基底映像。

後續步驟