比官方文件更有效的作法

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 為專案名稱並建立目錄

docker000

  1. 輸入 dotnet new console -o MyConsole 建立 MyConsole 專案,其專案類型為 console app

建立 Dockerfile


由於我們想要將 app 打包成 Docker image,因此要建立自己的 Dockerfile,Docker 才能依照此 Dockerfile 建立 Docker image。

Dockerfile

1
2
3
4
5
FROM microsoft/dotnet:runtime-deps
WORKDIR /app

COPY ./bin/Release/netcoreapp2.0/linux-x64/publish ./
ENTRYPOINT ["./MyConsole"]

第 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 指令 (如 RUNCMDENTRYPOINTCOPYADD …等) 的工作目錄。

以上表示 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

docker002

建立 Image


BuildDocker.sh

1
2
3
#!/bin/bash
dotnet publish -c Release -r linux-x64
docker build -t myconsole .

由於使用的 Docker image 是 microsoft/dotnet:runtime-deps,這表示我們必須使用 SCD 方式發布,dotnet publish 特別加上 -r linux-x64 使用 SCD,其 runtime 為 linux-x64

使用 docker buildDockerfile 建立 Docker image。

  • -t : tag,image 的名稱

docker004

1
~/MyConsole $ chmod +x ./BuildDocker.sh

使用 chmodBuildDocker.sh 能夠有 被執行 權限。

docker005

1
~/MyConsole $ ./BuildDocker.sh

執行 BuildDocker.sh 建立 Docker image。

docker001

1
~/MyConsole $ docker images

確認 myconsole image 已經被產生。

docker006

建立 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。

docker007

執行 Docker Compose


1
~/MyConsole $ docker-compose up

執行 docker-compose up 執行 docker-compose.yml 所定義的 container。

docker008

正確顯示 Hello World,表示 .NET Core App 已在 Docker 內執行成功。

結束 Docker Compose


1
~/MyProject $ docker-compose down

執行 docker-compose down 結束並刪除 container。

docker009

Summary


在 Microsoft 官方的 Learn Docker Basics with .NET Core 文件中,其 Dockerfile 如下:

1
2
3
4
5
6
7
8
9
10
11
FROM microsoft/dotnet:2.0-sdk
WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# copy and build everything else
COPY . ./
RUN dotnet publish -c Release -o out
ENTRYPOINT ["dotnet", "out/Hello.dll"]

第 1 行

1
FROM microsoft/dotnet:2.0-sdk

FROMmicrosoft/dotnet:2.0-sdk,也就是包含了 .NET Core CLI,所以 image 一定比較大。

第 4 行

1
2
3
4
5
6
7
# copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# copy and build everything else
COPY . ./
RUN dotnet publish -c Release -o out

將所有 source code 都複製進 image,在 docker build 時,在 image 內執行 dotnet restoredotnet publish,由於所有 source code 都進了 image,image 也一定比較大。

本文是 Host OS 以 SCD 方式 publish,僅將所需要的檔案複製進 image,如此 image 會小很多。

docker010

實際比較發現,若使用 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 上找到

Reference


.NET Core, Learn Docker Basics with .NET Core

2018-05-30