為 ASP.NET Core 建立 Multi-Platform image

最近公司正在逐步汰換使用年限到期的電腦:由 MacBook Pro (intel) 換為 MacBook Pro (M2 Pro),CPU 架構從 x86/x64 改為 arm64,許多軟體工具都需要改用特定版本才能正常使用,雖然在 M1 初問世就已經做過一輪測試跟 poc 也先做一些預先調整,其中一個就是啟用 buildx 來建立 Multi-Platform image,只是當初沒有經過全面驗證,這次實際更換機器時問題就陸續出現,今天就是要來紀錄一下 ASP.NET Core 的 Multi-Platform image 在 arm 上遇到的問題

基本環境說明

  1. macOS Ventura 13.4
  2. OrbStack 0.13.0(1910)
  3. docker images
    • mcr.microsoft.com/dotnet/sdk:6.0
    • mcr.microsoft.com/dotnet/aspnet:6.0
    • mcr.microsoft.com/dotnet/sdk:8.0-preview-alpine
    • mcr.microsoft.com/dotnet/aspnet:8.0-preview-alpine
  4. ASP.NET Core 預設 web api 專案範本
  5. build multiple-platform

    docker buildx build -f Dockerfile --platform linux/amd64,linux/arm64 -t yowko/multiplearch --push . 
    

設定方式

  1. 使用 .NET 8 以前 SDK

    主要的 dockerfile 結構是官方的,條件式內容則是參考 GitHub: f2calv/multi-arch-container-dotnet

  2. 使用 .NET 8 SDK (尚有相容性問題,詳細問題可以看 心得)

    這個是參考 Microsoft PM - Richard Lander 的文章:Improving multi-platform container support,dockerfile 也是官方的範例來的 samples/aspnetapp/Dockerfile.alpine-non-root

心得

  • 目前看到 .NET 8 的改變有兩個部份

    1. 新增 -a 參數,是 -r 的快捷鍵:${TARGETOS}/${TARGETARCH} 等於 ${TARGETPLATFORM},SDK 內部應該還有一層 mapping 做 RID 的轉換
    2. publish 時 -c Release 已改為預設參數
  • ASP.NET Core 針對 Multi-Platform 我自己覺得不同以往的部份

    1. stage 1 的 FROM 有指定 builder 的 image platform
    2. restore 有加上 -a 指定特定平台套件
    3. image size 差很多 ( sdk 8: 109MB, sdk 6: 306MB)
  • 我參考 Microsoft PM - Richard Lander 的文章:Improving multi-platform container support 使用 SDK 加入的參數並嘗試幾種不同方式得到幾個不同錯誤,紀錄一下

    1. 用相同 dockerfile 來 build .NET 6 的專案,出現需要安裝 .NET runtime 的提示訊息

      1wrongsdk

    2. 使用 mcr.microsoft.com/dotnet/sdk:8.0-preview-alpine builder ,runtime 改用 mcr.microsoft.com/dotnet/aspnet:6.0 出現找不到檔案

      2nofile

    3. 指定 --self-contained true 會 build fail

      3selfcontained

    4. 使用 .NET 8 的條件式來編譯出現找不到檔案

      2nofile

參考資訊

  1. docker Multi-platform images
  2. Enable using docker build –platform switch (easily)
  3. Improving multi-platform container support
  4. samples/aspnetapp/Dockerfile.alpine-non-root
  5. .NET RID 目錄