The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何將 ASP.NET Core 2.1 網站部署到 Docker 容器中

從 .NET Core 2.1 開始,無論是 .NET CoreASP.NET Core 專案,容器映像全部統一由 Docker Hub 上面的 microsoft/dotnet 專案提供。今天這篇文章,我就來說明如何將一份已經寫好的 ASP.NET Core 2.1 網站專案,透過 Docker 部署到容器中。

取得最新穩定版 Tag 名稱

你在建立容器映像時候,可以記得以下三個 Tag 名稱,這三個 Tag 會永遠指向最新版的 .NET Core 版本,分別是:

  • 2.1-sdk
    • 內建完整的 .NET Core 2.1 SDK 環境,可以幫助你建置 .NET Core 應用程式。
  • 2.1-runtime
    • 內建 .NET Core 2.1 Runtime 執行環境。(不含 SDK 工具)
    • 內建 Microsoft.NETCore.App 中繼套件與所有相依 NuGet 套件。
  • 2.1-aspnetcore-runtime
    • 內建 .NET Core 2.1 Runtime 執行環境。(不含 SDK 工具)
    • 內建 Microsoft.NETCore.App 中繼套件與所有相依 NuGet 套件。
    • 內建 Microsoft.AspNetCore.App 與 Microsoft.AspNetCore.All 中繼套件與所有相依 NuGet 套件。

上述三個 Tag 名稱會連結到各自的 Dockerfile 檔案,建議大家可以先行讀懂內容。

想了解 .NET Core 如何部署到容器中,參考 .NET Core Docker Samples 算是一個不錯的管道,因為有相當完整的範例可參考。

請注意:如果你已經下載過這三個 Tag 的容器映像(Docker Image),預設在執行 docker build 的過程,並不會自動到 Docker Hub 下載最新版本。如果你要更新到最近的穩定版,必須透過 docker pull 重新下載才行!

認識 ASP.NET Core 的 Docker 容器範例

我們可以從 ASP.NET Core Docker Sample 文件中,得知許多建置 Docker 容器映像的範例。我們就從該文章的第一個簡易範例來看,其重點如下:

  1. 該 Dockerfile 範例使用了 multi-stage builds 建置技巧,並分成兩個步驟執行:
    1. 先透過 microsoft/dotnet:2.1-sdk 建置 ASP.NET Core 應用程式
    2. 再透過 microsoft/dotnet:2.1-aspnetcore-runtime 將建置好的 ASP.NET Core 應用程式,封裝進 ASP.NET Core 執行環境容器中。
  2. 在第一個 stage build 中,又分成兩個步驟:
    1. 先取得 *.sln*.csproj 檔案,並還原專案中會用到的 NuGet 套件。
    2. 複製完整的 ASP.NET Core 原始碼到目錄中,並執行 dotnet publish 發布應用程式到 out 資料夾下。
  3. 在第二個 stage build 中,複製第一個 stage build 的完整發布結果到新的容器中,然後設定 ENTRYPOINT 指定容器的啟動命令。
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /app

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

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


FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
WORKDIR /app
COPY --from=build /app/aspnetapp/out ./
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

完整的實作練習流程如下:

  1. 取得範例原始碼

    git clone https://github.com/dotnet/dotnet-docker.git
    cd dotnet-docker/samples/aspnetapp
    
  2. 建置 aspnetapp 容器映像

    docker build -t aspnetapp .
    
  3. 執行自訂的 aspnetapp 容器

    docker run -d --name=myapp --rm -p 8000:80 aspnetapp
    

    連到 http://localhost:8000/ 就可以看到網頁執行。

  4. 停止容器

    docker stop myapp
    

這份 ASP.NET Core 容器範例最有趣的地方是,他可以讓你在本機不需要安裝任何 .NET Core SDK 環境,透過預先製作好的 Docker Image 就可以讓你快速的建置與發行專案。這樣的設計,最能展現效益的地方,就是 CI/CD 的過程會非常簡單,完全沒有環境的相依性!

進一步認識 microsoft/dotnet:2.1-aspnetcore-runtime 容器映像

如果深入查看這份 microsoft/dotnet:2.1-aspnetcore-runtime 容器映像,你會發現他的 Base Image 是 microsoft/dotnet:2.1-runtime-deps-stretch-slim,其內容如下:

FROM debian:stretch-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        ca-certificates \
        \
# .NET Core dependencies
        libc6 \
        libgcc1 \
        libgssapi-krb5-2 \
        libicu57 \
        liblttng-ust0 \
        libssl1.0.2 \
        libstdc++6 \
        zlib1g \
    && rm -rf /var/lib/apt/lists/*

# Configure Kestrel web server to bind to port 80 when present
ENV ASPNETCORE_URLS=http://+:80 \
    # Enable detection of running in a container
    DOTNET_RUNNING_IN_CONTAINER=true

最後兩行,定義了兩個環境變數,尤其是 ASPNETCORE_URLS 最為重要,這個環境變數決定了你的 ASP.NET Core 應用程式要對外 Listen 哪一個 IP:Ports,這裡的 + 代表的是 Binding 所有的本機 IP 位址,而 80 就代表了只 Listen 埠號 80 (這裡是指容器內的 Port 80)。也因此,我們在執行這個容器時,需要特別加上 -p 8000:80 的關係,這代表著我們容器主機的 8000 Port 會對應到容器中的 80 Port 的意思。

docker run -d -p 8000:80 aspnetapp

如何建立含有 HTTPS 加密連線的 ASP.NET Core 網站容器

我們在建立容器映像的時候,我們都會大量利用「環境變數」來調整容器執行時期的運作邏輯,例如指定 IP:Port,或是設定 TLS/SSL 憑證金鑰等等。如果你想了解如何部署含有 HTTPS 加密連線的 ASP.NET Core 2.1 網站在 Docker 容器中,可以參考 Hosting ASP.NET Core Images with Docker over HTTPS 這份文件下去設定。

如果你在 Windows 環境下使用 Linux 容器,可以參考以下步驟進行測試:

  1. 先建立開發測試用的自簽憑證

    dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p crypticpwd
    dotnet dev-certs https --trust
    
  2. 再透過環境變數指定相關憑證與相關參數

    你只要透過指定「環境變數」就可以順利將先前建立建立好的 aspnetapp 容器映像,自動跑成含有 HTTPS 加密連線的 Kestrel 伺服器。

    docker run --rm -it -p 8000:80 -p 8001:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_Kestrel__Certificates__Default__Password="crypticpwd" -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx -v %USERPROFILE%\.aspnet\https:/https/ aspnetapp
    

    連到 https://localhost:8001/ 就可以看到 HTTPS 加密網頁執行。

相關連結

留言評論