在本教學課程中,您將瞭解如何使用 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 Community Edition
  • Dockerfile 和 .NET 範例應用程式的暫存工作資料夾 。 在本教學課程中,docker-working 名稱 會當做工作資料夾使用。
  • 建立 .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!

    cd App
    dotnet run
    Hello World!
    

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

    如果您使用 Visual Studio Code,請從上一個終端機會話輸入下列命令:

    code .
    

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

    Program.cs 看起來應該像下列 C# 程式碼:

    Console.WriteLine("Hello World!");
    

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

    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));

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

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

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

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

    發佈 .NET 應用程式

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

    dotnet publish -c Release
    

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

    Windows Linux
    dir .\bin\Release\net7.0\publish\
        Directory: C:\Users\dapine\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
    

    ls使用 命令來取得目錄清單,並確認已 建立 DotNet.Docker.dll 檔案。

    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
    

    建立 Dockerfile

    docker build 命令會使用 Dockerfile 檔案來建立容器映像。 此檔案是名為 Dockerfile 的文字檔,沒有副檔名。

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

    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"]

    ASP.NET Core 執行時間映射是刻意在這裡使用,雖然 mcr.microsoft.com/dotnet/runtime:7.0 可以使用映射。

    Dockerfile 會使用多階段組建,藉由分層建置,只保留必要的成品,將映射的最終大小優化。 如需詳細資訊,請參閱 Docker Docs:多階段組建

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

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

    📁 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 📁
                └──...
    

    從終端機執行下列命令:

    docker build -t counter-image -f Dockerfile .
    

    Docker 將會處理 Dockerfile 中的每一行。 .命令中的 docker build 會設定映射的組建內容。 參數 -f 是 Dockerfile 的路徑 。 此命令會建置映射,並建立名為 counter-image 的本機存放庫,指向該映射。 當此命令完成之後,執行 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:7.0
    WORKDIR /App
    COPY --from=build-env /build/out .
    ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
    

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

    命令會將 WORKDIR 容器內的目前目錄 變更為 App

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

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

    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 0.2s (14/14) FINISHED
     => [internal] load build definition from Dockerfile                                  0.0s
     => => transferring dockerfile: 32B                                                   0.0s
     => [internal] load .dockerignore                                                     0.0s
     => => transferring context: 2B                                                       0.0s
     => [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:7.0                  0.1s
     => [internal] load metadata for mcr.microsoft.com/dotnet/sdk:7.0                     0.1s
     => [build-env 1/5] FROM mcr.microsoft.com/dotnet/sdk:7.0@sha256:80dce5844ecdc719704  0.0s
     => [internal] load build context                                                     0.0s
     => => transferring context: 4.00kB                                                   0.0s
     => [stage-1 1/3] FROM mcr.microsoft.com/dotnet/aspnet:7.0@sha256:8dd65c009a093947cb  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.0s
     => => exporting layers                                                               0.0s
     => => writing image sha256:2094c4692eeaeabebfa2cc68f77907e9ca8455deea948012690c6639  0.0s
     => => naming to docker.io/library/counter-image                                      0.0s
    docker images
    REPOSITORY      TAG       IMAGE ID       CREATED              SIZE
    counter-image   latest    2094c4692eea   About a minute ago   212MB
    

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

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

    docker create --name core-counter counter-image
    

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

    d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
    

    若要查看「所有」容器的清單,請使用 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
    

    容器是以特定名稱 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
    docker attach --sig-proxy=false core-counter
    Counter: 17
    Counter: 18
    Counter: 19
    

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

    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
    

    容器也會將參數傳遞至 .NET 應用程式的執行。 若要指示 .NET 應用程式只計算為 3,請傳入 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。 視需要編輯命令。

    Windows Linux

    在此範例中,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
    

    在此範例中,ENTRYPOINT 會變更為 bash。 執行 exit 命令以結束程序並停止容器。

    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
    root@9f8de8fbd4a8:/App# exit
    

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

  • docker build
  • docker run
  • docker ps
  • docker stop
  • docker rm
  • docker rmi
  • docker image
  • 在本教學課程中,您已建立容器和映射。 您可以視需要刪除這些資源。 使用下列命令

  • 列出所有容器

    docker ps -a
    
  • 停止依其名稱執行的容器。

    docker stop core-counter
    
    docker rm core-counter
    

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

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

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

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

  • 了解如何將 ASP.NET Core 應用程式容器化。
  • 嘗試 ASP.NET Core 微服務教學課程。 \(英文\)
  • 檢閱支援容器的 Azure 服務。
  • 了解 Dockerfile 命令。 \(英文\)
  • 探索 Visual Studio 的容器工具
  •