如何將 .NET Core App 打包成 Docker Image ?
Docker 除了用在測試外,尚可將整個 app 打包成 Docker image,配合 Docker Compose 與其他 Microservice,可以直接用在 production。
Version
macOS High Sierra 10.13.4
Docker for Mac 18.03-ce-mac65 (24312)
.NET Core 2.0.7
VS Code 1.23.1
建立 Console App
1 | $ dotnet new console -o MyConsole |
使用 dotnet new
建立 .NET Core App。
- new : 建立 project
- console : 建立 console 類型 project
- -o : 以 MyConsole 為專案名稱並建立目錄
- 輸入
dotnet new console -o MyConsole
建立MyConsole
專案,其專案類型為console app
建立 Dockerfile
由於我們想要將 app 打包成 Docker image,因此要建立自己的 Dockerfile
,Docker 才能依照此 Dockerfile
建立 Docker image。
Dockerfile
1 | FROM microsoft/dotnet:runtime-deps |
第 1 行
1 | FROM microsoft/dotnet:runtime-deps |
FROM
為 Dockerfile 指令,表示以哪一個 image 為基礎建立自己的 image。
其中 microsoft/dotnet:runtime-deps
是 Microsoft 專為 .NET Core 準備的 Docker image,此 image 不含 .NET Core runtime,僅包含所需要的 Linux library,是最小包的 image。
第 2 行
1 | WORKDIR /app |
WORKDIR
為 Dockerfile 指令,表示其他 Dockerfile 指令 (如 RUN
、CMD
、ENTRYPOINT
、COPY
與 ADD
…等) 的工作目錄。
以上表示 WORKDIR
為 /app
,若 /app
目錄不存在會自動建立。
第 4 行
1 | COPY ./bin/Release/netcoreapp2.0/linux-x64/publish ./ |
COPY
為 Dockerfile 指令,表示將 Host OS 的檔案或目錄,複製到 container 內。
第 1 個參數為 Host OS 檔案或目錄,第 2 個參數為 container 檔案或目錄。
以上表示僅將以 SCD 方式發布的 Linux App 複製到 container 內。
第 5 行
1 | ENTRYPOINT ["./MyConsole"] |
ENTRYPOINT
為 Dockerfile 指令,表示 container 一啟動時,該執行什麼指令。
以上表示當 container 一啟動時,將執行 ./MyConsole
。
建立 Image
BuildDocker.sh
1 | #!/bin/bash |
由於使用的 Docker image 是 microsoft/dotnet:runtime-deps
,這表示我們必須使用 SCD 方式發布,dotnet publish
特別加上 -r linux-x64
使用 SCD,其 runtime 為 linux-x64
。
使用 docker build
由 Dockerfile
建立 Docker image。
- -t :
t
ag,image 的名稱
1 | ~/MyConsole $ chmod +x ./BuildDocker.sh |
使用 chmod
讓 BuildDocker.sh
能夠有 被執行
權限。
1 | ~/MyConsole $ ./BuildDocker.sh |
執行 BuildDocker.sh
建立 Docker image。
1 | ~/MyConsole $ docker images |
確認 myconsole
image 已經被產生。
建立 Docker Compose
docker-compose.yml
1 | version: "3" services: net-core: image: myconsole container_name: MyConsole |
第 5 行
1 | image: myconsole |
使用自己剛剛建立的 mycosole
image。
第 6 行
1 | container_name: MyConsole |
建立名為 MyConsole
的 container。
執行 Docker Compose
1 | ~/MyConsole $ docker-compose up |
執行 docker-compose up
執行 docker-compose.yml
所定義的 container。
正確顯示 Hello World
,表示 .NET Core App 已在 Docker 內執行成功。
結束 Docker Compose
1 | ~/MyProject $ docker-compose down |
執行 docker-compose down
結束並刪除 container。
Summary
在 Microsoft 官方的 Learn Docker Basics with .NET Core 文件中,其 Dockerfile 如下:
1 | FROM microsoft/dotnet:2.0-sdk |
第 1 行
1 | FROM microsoft/dotnet:2.0-sdk |
FROM
為 microsoft/dotnet:2.0-sdk
,也就是包含了 .NET Core CLI,所以 image 一定比較大。
第 4 行
1 | # copy csproj and restore as distinct layers |
將所有 source code 都複製進 image,在 docker build
時,在 image 內執行 dotnet restore
與 dotnet publish
,由於所有 source code 都進了 image,image 也一定比較大。
本文是 Host OS 以 SCD 方式 publish,僅將所需要的檔案複製進 image,如此 image 會小很多。
實際比較發現,若使用 Microsoft 官方作法,Docker image 為 1.84 GB,但使用本文方式,只有 218 MB,非常適合 production 使用。
Conclusion
- 將 .NET Core console app 打包成 Docker image 後,就可以跨平台執行此 image
- 此範例雖然是 console app,事實上將 ASP.NET Core 打包成 Docker image 也是類似以上流程
- 使用本文的方式,Docker image 的 size 將會有效的縮小
Sample Code
完整的範例可以在我的 GitHub 上找到