共用方式為


容器化 .NET 應用程式參考

在本參考文章中,您將瞭解如何設定將 .NET 應用程式發佈為容器時所產生的容器映像。 本文涵蓋您可以設定的各種屬性,以控制映像、執行環境,以及容器啟動時執行的命令。

設定容器映像

您可以透過 MSBuild 屬性控制產生的容器的許多層面。 一般而言,如果您在 Dockerfile 中使用 命令來設定某些設定,您可以透過 MSBuild 執行相同的動作。

注意

唯一的例外狀況是 RUN 命令。 由於容器的建置方式,因此無法模擬這些容器。 如果您需要這項功能,請考慮使用 Dockerfile 來建置容器映射。

使用 .NET SDK 無法執行 RUN 命令。 這些命令通常用來安裝某些 OS 套件,或建立新的 OS 使用者,或任何數目的任意專案。 如果您想要繼續使用 .NET SDK 容器建置功能,您可以改為使用這些變更來建立自定義基底映射,然後使用這個基底映像。 如需詳細資訊,請參閱 ContainerBaseImage

ContainerArchiveOutputPath

若要在 tar.gz 封存內建立容器映像,請使用 ContainerArchiveOutputPath 屬性。 如果您的工作流程並不簡單,而且要求您在推送影像之前先透過影像執行掃描工具,這項功能就很有用。 建立封存之後,您就可以將它移動、掃描或載入本機 Docker 工具鏈。

若要發佈至封存,請將 ContainerArchiveOutputPath 屬性新增至您的 dotnet publish 命令,例如:

dotnet publish \
  -p PublishProfile=DefaultContainer \
  -p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz

您可以指定資料夾名稱或具有特定檔案名的路徑。 如果您指定資料夾名稱,則針對映像封存盤案產生的檔案名會命名為 $(ContainerRepository).tar.gz。 這些封存可以包含其中多個標籤,只有針對所有 ContainerImageTags建立單一檔案。

容器映像命名組態

容器映像遵循特定的命名慣例。 映像的名稱是由數個元件、登錄、選擇性埠、存放庫和選擇性標籤和系列所組成。

REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]]

例如,請考慮完整 mcr.microsoft.com/dotnet/runtime:8.0-alpine 映射名稱:

  • mcr.microsoft.com 是登錄(在此案例中代表Microsoft容器登錄)。
  • dotnet/runtime 是存放庫(但有些人認為這是 user/repository)。
  • 8.0-alpine 是標籤和系列(系列是選擇性規範,有助於釐清OS封裝)。

下列各節所述的一些屬性會對應至管理所產生映像名稱的部分。 請考慮下表,對應映像名稱和組建屬性之間的關聯性:

映射名稱部分 MSBuild 屬性 範例值
REGISTRY[:PORT] ContainerRegistry mcr.microsoft.com:443
PORT ContainerPort :443
REPOSITORY ContainerRepository dotnet/runtime
TAG ContainerImageTag 8.0
FAMILY ContainerFamily -alpine

下列各節說明可用來控制產生的容器映像的各種屬性。

ContainerBaseImage

容器基底映像屬性會控制用來作為映像基礎的映像。 根據預設,系統會根據項目的屬性推斷下列值:

  • 如果您的項目是獨立的,則會使用 mcr.microsoft.com/dotnet/runtime-deps 映射作為基底映射。
  • 如果您的專案是 ASP.NET Core 專案,則會使用 mcr.microsoft.com/dotnet/aspnet 映射作為基底映像。
  • 否則,mcr.microsoft.com/dotnet/runtime 映射會當做基底映像使用。

影像的標記會推斷為所選 TargetFramework的數值元件。 例如,以 net6.0 為目標的專案會產生推斷基底映射的 6.0 標記,而 net7.0-linux 專案會使用 7.0 標記等等。

如果您在這裡設定值,您應該將映像的完整名稱設定為基底,包括您偏好的任何標記:

<PropertyGroup>
    <ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:8.0</ContainerBaseImage>
</PropertyGroup>

使用 .NET SDK 8.0.200 版時,已改善 ContainerBaseImage 推斷,以優化大小和安全性:

  • linux-musl-x64linux-musl-arm64 執行時間識別碼為目標,自動選擇 alpine 影像變體,以確保您的項目執行:
    • 如果專案使用 PublishAot=true,則基底映像 nightly/runtime-depsjammy-chiseled-aot 變體,以獲得最佳大小和安全性。
    • 如果專案使用 InvariantGlobalization=false,則會使用 -extra 變體來確保當地語系化仍可運作。

如需有關映像變體大小和特性的詳細資訊,請參閱.NET 8.0 容器映射大小報表。

ContainerFamily

從 .NET 8 開始,您可以使用 ContainerFamily MSBuild 屬性,選擇不同系列Microsoft提供的容器映射做為應用程式的基底映射。 設定時,此值會附加至所選 TFM 特定標籤的結尾,變更提供的標記。 例如,若要使用 .NET 基底映射的 Alpine Linux 變體,您可以將 ContainerFamily 設定為 alpine

<PropertyGroup>
    <ContainerFamily>alpine</ContainerFamily>
</PropertyGroup>

上述項目組態會產生 .NET 8 目標應用程式 8.0-alpine 的最終標記。

此欄位是自由格式的,通常可用來選取不同的操作系統散發套件、預設套件元件元件組態或任何其他 類別, 基底映像的變更。 設定 ContainerBaseImage 時,會忽略此欄位。 如需詳細資訊,請參閱.NET 容器映像。

ContainerRuntimeIdentifier(s)

如果 ContainerRuntimeIdentifier 支援多個平臺,ContainerBaseImage 屬性會指定容器的OS和架構。 例如,mcr.microsoft.com/dotnet/runtime 映像支援 linux-x64linux-armlinux-arm64win10-x64。 根據預設,這會設定為發佈容器時所使用的 RuntimeIdentifier。 一般而言,您不需要明確設定此屬性;請改用 -r 選項搭配 dotnet publish 命令。 如果所選的映像不支援指定的 RuntimeIdentifier,則錯誤表示支援的標識碼。

您一律可以將 ContainerBaseImage 屬性設定為完整映像名稱,包括標記,以避免完全需要使用這個屬性。

<PropertyGroup>
    <ContainerRuntimeIdentifier>linux-arm64</ContainerRuntimeIdentifier>
</PropertyGroup>

若要為多架構映像指定多個容器運行時間識別碼,請在 ContainerRuntimeIdentifiers 屬性中使用以分號分隔的運行時間標識元集,類似於設定多個 TargetFrameworks

<PropertyGroup>
    <ContainerRuntimeIdentifiers>linux-x64;linux-arm64</ContainerRuntimeIdentifiers>
</PropertyGroup>

如需 .NET 所支援之執行時間識別碼的詳細資訊,請參閱 RID 目錄

ContainerRegistry

容器登錄屬性會控制目的地登錄,將推送新建立映像的位置。 根據預設,它會推送至本機 Docker 精靈,但您也可以指定遠端登錄。 使用需要驗證的遠端登錄時,您可以使用已知的 docker login 機制進行驗證。 如需詳細資訊,請參閱 向容器登錄進行驗證 以取得詳細數據。 如需使用這個屬性的具體範例,請考慮下列 XML 範例:

<PropertyGroup>
    <ContainerRegistry>registry.mycorp.com:1234</ContainerRegistry>
</PropertyGroup>

此工具支持發行至任何支援 Docker 登錄 HTTP API V2的登錄。 這包括下列明確登錄(而且可能更隱含地包含):

如需使用這些登入的注意事項,請參閱 登錄特定注意事項

ContainerRepository

容器存放庫是映像本身的名稱,例如,dotnet/runtimemy-app。 根據預設,會使用專案的 AssemblyName

<PropertyGroup>
    <ContainerRepository>my-app</ContainerRepository>
</PropertyGroup>

影像名稱包含一或多個斜線分隔區段,每個區段只能包含小寫英數位元、句點、底線和虛線,而且必須以字母或數字開頭。 任何其他字元都會導致擲回錯誤。

ContainerImageTag(s)

容器映像標籤屬性會控制為映像產生的標記。 若要指定單一標籤使用 ContainerImageTag,並針對多個標籤使用 ContainerImageTags

重要

當您使用 ContainerImageTags時,最後會有多個影像,每個唯一標記一個。

標籤通常用來參考不同版本的應用程式,但它們也可以參考不同的操作系統散發套件,甚至是不同的元件。

從 .NET 8 開始,如果未提供標籤,則預設值為 latest

若要覆寫預設值,請指定下列其中一項:

<PropertyGroup>
    <ContainerImageTag>1.2.3-alpha2</ContainerImageTag>
</PropertyGroup>

若要指定多個標記,請在 ContainerImageTags 屬性中使用以分號分隔的標記集,類似於設定多個 TargetFrameworks

<PropertyGroup>
    <ContainerImageTags>1.2.3-alpha2;latest</ContainerImageTags>
</PropertyGroup>

標籤最多只能包含127個英數位元、句點、底線和虛線。 它們必須以英數位元或底線開頭。 任何其他表單都會導致擲回錯誤。

注意

使用 ContainerImageTags 或任何需要設定 ; 分隔值的 MSBuild 屬性時。 如果您要從命令行呼叫 dotnet publish(如同大部分 CI/CD 環境的情況),您必須瞭解環境無法釐清分隔符和引號的限制,因此需要適當的逸出。 這在 PowerShell 和 Bash 之間有所不同。 請考慮下列 dotnet publish 命令在其各自的環境中:

dotnet publish --os linux --arch x64 /t:PublishContainer /p:ContainerImageTags=`"1.2.3-alpha2`;latest`"

在 PowerShell 中,必須逸出 ;" 字元。

dotnet publish --os linux --arch x64 /t:PublishContainer /p:ContainerImageTags=\"1.2.3-alpha2;latest\"

在Bash中,只需要逸出 " 字元。

這會產生兩個影像:my-app:1.2.3-alpha2my-app:latest

提示

如果您遇到 ContainerImageTags 屬性的問題,請考慮改為將環境變數的範圍設定為 ContainerImageTags

$Env:ContainerImageTags='1.2.3;latest'; dotnet publish --os linux --arch x64 /t:PublishContainer

ContainerLabel

容器標籤會將元數據標籤新增至容器。 卷標通常用來儲存版本和撰寫元數據,以供安全性掃描器和其他基礎結構工具使用。 您可以指定任意數目的容器標籤。

ContainerLabel 節點有兩個屬性:

  • Include:標籤的索引鍵。
  • Value:標籤的值(這可能是空的)。
<ItemGroup>
    <ContainerLabel Include="org.contoso.businessunit" Value="contoso-university" />
</ItemGroup>

如需預設建立的標籤清單,請參閱預設容器標籤。

設定容器執行

若要控制容器的執行,您可以使用下列 MSBuild 屬性。

ContainerWorkingDirectory

容器工作目錄節點會控制容器的工作目錄,如果不是執行其他命令,則會在內執行命令的目錄。

根據預設,/app 目錄值會當做工作目錄使用。

<PropertyGroup>
    <ContainerWorkingDirectory>/bin</ContainerWorkingDirectory>
</PropertyGroup>

ContainerPort

容器埠會將傳輸控制通訊協定 (TCP) 或用戶數據報通訊協定 (UDP) 埠新增至容器的已知埠清單。 這可讓 Docker 等容器運行時間自動將這些埠對應至主電腦。 這通常用來做為容器的檔,但也可以用來啟用自動埠對應。

ContainerPort 節點有兩個屬性:

  • Include:要公開的埠號碼。
  • Type:預設為 tcp,有效值為 tcpudp
<ItemGroup>
    <ContainerPort Include="80" Type="tcp" />
</ItemGroup>

從 .NET 8 開始,ContainerPort 會在未根據數個已知 ASP.NET 環境變數明確提供時推斷:

  • ASPNETCORE_URLS
  • ASPNETCORE_HTTP_PORTS
  • ASPNETCORE_HTTPS_PORTS

如果存在這些環境變數,其值會剖析並轉換成 TCP 埠對應。 如果您的基底映像存在,或透過 ContainerEnvironmentVariable 專案所定義的環境變數,則會從基底映像讀取這些環境變數。 如需詳細資訊,請參閱 ContainerEnvironmentVariable

ContainerEnvironmentVariable

容器環境變數節點可讓您將環境變數新增至容器。 在容器中執行的應用程式可以立即存取環境變數,而且通常用來變更執行中應用程式的運行時間行為。

ContainerEnvironmentVariable 節點有兩個屬性:

  • Include:環境變數的名稱。
  • Value:環境變數的值。
<ItemGroup>
  <ContainerEnvironmentVariable Include="LOGGER_VERBOSITY" Value="Trace" />
</ItemGroup>

如需詳細資訊,請參閱.NET 環境變數。

注意

發佈容器映射時,目前無法從 .NET CLI 設定環境變數。 如需詳細資訊,請參閱 GitHub:.NET SDK 容器組建

設定容器命令

根據預設,容器工具會使用應用程式產生的AppHost二進位檔來啟動您的應用程式(如果您的應用程式使用AppHost),或 dotnet 命令加上您應用程式的 DLL。

不過,您可以使用 ContainerAppCommandContainerAppCommandArgsContainerDefaultArgsContainerAppCommandInstruction組合來控制應用程式的執行方式。

這些不同的組態點存在,因為不同的基底映像會使用不同的容器組合,ENTRYPOINTCOMMAND 屬性,而且您想要能夠支持它們。 預設值應該適用於大部分的應用程式,但如果您想要自訂應用程式啟動行為,您應該:

  • 識別要執行的二進位檔,並將其設定為 ContainerAppCommand
  • 識別您的應用程式執行所需的自變數 ,並將其設定為 ContainerAppCommandArgs
  • 識別哪些自變數 選擇性,並可由使用者覆寫,並將其設定為 ContainerDefaultArgs
  • 將 [ContainerAppCommandInstruction] 設定為 [DefaultArgs

如需詳細資訊,請參閱下列組態專案。

ContainerAppCommand

應用程式命令組態專案是您應用程式的邏輯進入點。 對於大部分的應用程式而言,這是 AppHost,這是應用程式產生的可執行檔二進位檔。 如果您的應用程式不會產生 AppHost,則此指令通常會 dotnet <your project dll>。 這些值會在基底容器中的任何 ENTRYPOINT 之後套用,或直接在未定義任何 ENTRYPOINT 時套用。

ContainerAppCommand 組態具有單一 Include 屬性,代表在 entrypoint 命令中使用的命令、選項或自變數:

<ItemGroup Label="ContainerAppCommand Assignment">
  <!-- This is how you would start the dotnet ef tool in your container -->
  <ContainerAppCommand Include="dotnet" />
  <ContainerAppCommand Include="ef" />

  <!-- This shorthand syntax means the same thing, note the semicolon separating the tokens. -->
  <ContainerAppCommand Include="dotnet;ef" />
</ItemGroup>

ContainerAppCommandArgs

此應用程式命令自變數組態專案代表應用程式應套用至 ContainerAppCommand的任何邏輯必要自變數。 根據預設,應用程式不會產生任何專案。 存在時,args 會在執行容器時套用至您的容器。

ContainerAppCommandArgs 組態具有單一 Include 屬性,代表要套用至 ContainerAppCommand 命令的選項或自變數。

<ItemGroup>
  <!-- Assuming the ContainerAppCommand defined above,
       this would be the way to force the database to update.
  -->
  <ContainerAppCommandArgs Include="database" />
  <ContainerAppCommandArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerAppCommandArgs Include="database;update" />
</ItemGroup>

ContainerDefaultArgs

這個預設自變數組態專案代表您應用程式的任何用戶可覆寫自變數。 這是提供預設值的好方法,您的應用程式可能需要以輕鬆啟動的方式執行,但仍易於自定義。

ContainerDefaultArgs 組態具有單一 Include 屬性,代表要套用至 ContainerAppCommand 命令的選項或自變數。

<ItemGroup>
  <!-- Assuming the ContainerAppCommand defined above,
       this would be the way to force the database to update.
  -->
  <ContainerDefaultArgs Include="database" />
  <ContainerDefaultArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerDefaultArgs Include="database;update" />
</ItemGroup>

ContainerAppCommandInstruction

應用程式命令指令組態可協助控制 ContainerEntrypointContainerEntrypointArgsContainerAppCommandContainerAppCommandArgsContainerDefaultArgs 的組合方式,以形成容器中執行的最終命令。 這在很大程度上取決於基底映射中是否存在 ENTRYPOINT。 此屬性接受三個值之一:"DefaultArgs""Entrypoint""None"

  • Entrypoint
    • 在此模式中,進入點是由 ContainerAppCommandContainerAppCommandArgsContainerDefaultArgs所定義。
  • None
    • 在此模式中,進入點是由 ContainerEntrypointContainerEntrypointArgsContainerDefaultArgs所定義。
  • DefaultArgs
    • 這是最複雜的模式,如果沒有任何 ContainerEntrypoint[Args] 專案存在,則會使用 ContainerAppCommand[Args]ContainerDefaultArgs 來建立進入點和命令。 基底映像的基底映射進入點會略過硬式編碼來 dotnet/usr/bin/dotnet,讓您可以完全控制。
    • 如果 ContainerEntrypointContainerAppCommand 都存在,則 ContainerEntrypoint 會變成進入點,ContainerAppCommand 變成命令。

注意

自 .NET 8 起,ContainerEntrypointContainerEntrypointArgs 組態專案已被取代。

重要

這是針對進階使用者而言,大部分的應用程式都不應該需要以這個程度自定義其進入點。 如需詳細資訊,以及如果您想要提供案例的使用案例,請參閱 GitHub:.NET SDK 容器建置討論

ContainerUser

用戶組態屬性會控制容器執行時的預設使用者。 這通常用來以非根使用者身分執行容器,這是安全性的最佳做法。 此設定有幾個條件約束需要注意:

  • 它可以採用各種形式:用戶名稱、linux 使用者標識碼、組名、linux 群組標識碼、username:groupname和其他標識符變體。
  • 映像上沒有指定之使用者或群組的驗證。
  • 變更使用者可以改變應用程式的行為,特別是 檔案系統 許可權等事項。

此欄位預設值會因專案 TFM 與目標作業系統而異:

  • 如果您要以 .NET 8 或更新版本為目標,並使用Microsoft運行時間映射,則:
    • 在 Linux 上,會使用無根使用者 app(雖然其使用者識別符會參考它)
    • 在 Windows 上使用無根使用者 ContainerUser
  • 否則,不會使用預設 ContainerUser
<PropertyGroup>
  <ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>

提示

APP_UID 環境變數可用來在容器中設定用戶資訊。 此值可能來自基底映射中定義的環境變數(如同 .NET 映射所做的Microsoft),或者您可以透過 ContainerEnvironmentVariable 語法自行設定。

若要將您的應用程式設定為以根使用者身分執行,請將 ContainerUser 屬性設定為 root。 在您的項目檔中,新增下列專案:

<PropertyGroup>
  <ContainerUser>root</ContainerUser>
</PropertyGroup>

或者,您可以從命令行呼叫 dotnet publish 時設定此值:

dotnet publish -p ContainerUser=root

默認容器標籤

卷標通常用來在容器映像上提供一致的元數據。 此套件提供一些默認標籤,以鼓勵產生影像的更佳維護性。

  • org.opencontainers.image.created 設定為目前值 DateTime.UtcNow的 ISO 8601 格式。

如需詳細資訊,請參閱 在現有標籤基礎結構上實作傳統標籤。

另請參閱