容器化 .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 核心项目,则
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-x64
或linux-musl-arm64
运行时标识符,自动选择alpine
映像变体以确保项目运行:- 如果项目使用
PublishAot=true
,则基本映像nightly/runtime-deps
jammy-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
属性指定容器的 OS 和体系结构(如果 ContainerBaseImage
支持多个平台)。 例如,mcr.microsoft.com/dotnet/runtime
映像支持 linux-x64
、linux-arm
、linux-arm64
和 win10-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/runtime
或 my-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-alpha2
和 my-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
,有效值为tcp
或udp
。
<ItemGroup>
<ContainerPort Include="80" Type="tcp" />
</ItemGroup>
从 .NET 8 开始,如果未根据几个已知的 ASP.NET 环境变量显式提供,则会推断 ContainerPort
:
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 启动应用。
但是,可以使用 ContainerAppCommand
、ContainerAppCommandArgs
、ContainerDefaultArgs
和 ContainerAppCommandInstruction
的某种组合来控制应用的执行方式。
存在这些不同的配置点,因为不同的基本映像使用不同的容器组合 ENTRYPOINT
和 COMMAND
属性,并且你希望能够支持所有这些配置点。 默认值应适用于大多数应用,但如果要自定义应用启动行为,则应:
- 标识要运行的二进制文件并将其设置为
ContainerAppCommand
- 确定应用程序运行所需的参数 并将其设置为
ContainerAppCommandArgs
- 确定哪些参数(如果有)可选,可由用户重写,并将其设置为
ContainerDefaultArgs
- 将
ContainerAppCommandInstruction
设置为DefaultArgs
有关详细信息,请参阅以下配置项目。
ContainerAppCommand
应用命令配置项是应用的逻辑入口点。 对于大多数应用,这是 AppHost,它是应用的生成的可执行二进制文件。 如果应用未生成 AppHost,则此命令通常 dotnet <your project dll>
。 这些值在基本容器中的任何 ENTRYPOINT
之后应用,或者如果未定义任何 ENTRYPOINT
,则直接应用这些值。
ContainerAppCommand
配置具有单个 Include
属性,该属性表示在入口点命令中使用的命令、选项或参数:
<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
的应用的任何逻辑必需参数。 默认情况下,不会为应用生成任何内容。 如果存在,则参数在运行时将应用到容器。
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
应用命令指令配置有助于控制 ContainerEntrypoint
、ContainerEntrypointArgs
、ContainerAppCommand
、ContainerAppCommandArgs
和 ContainerDefaultArgs
的组合方式,形成在容器中运行的最终命令。 这在很大程度上取决于基础映像中是否存在 ENTRYPOINT
。 此属性采用三个值之一:"DefaultArgs"
、"Entrypoint"
或 "None"
。
-
Entrypoint
:- 在此模式下,入口点由
ContainerAppCommand
、ContainerAppCommandArgs
和ContainerDefaultArgs
定义。
- 在此模式下,入口点由
-
None
:- 在此模式下,入口点由
ContainerEntrypoint
、ContainerEntrypointArgs
和ContainerDefaultArgs
定义。
- 在此模式下,入口点由
-
DefaultArgs
:- 这是最复杂的模式-如果不存在任何
ContainerEntrypoint[Args]
项,则使用ContainerAppCommand[Args]
和ContainerDefaultArgs
来创建入口点和命令。 将跳过基本映像的基映像入口点,这些基映像硬编码为dotnet
或/usr/bin/dotnet
,以便完全控制。 - 如果同时存在
ContainerEntrypoint
和ContainerAppCommand
,则ContainerEntrypoint
将成为入口点,ContainerAppCommand
成为命令。
- 这是最复杂的模式-如果不存在任何
注意
自 .NET 8 起,ContainerEntrypoint
和 ContainerEntrypointArgs
配置项目已弃用。
重要
这适用于大多数高级用户的应用不需要将入口点自定义到此程度。 有关详细信息,如果想要为方案提供用例,请参阅 GitHub:.NET SDK 容器生成讨论。
ContainerUser
用户配置属性控制容器运行方式的默认用户。 这通常用于将容器作为非根用户运行,这是安全性的最佳做法。 此配置需要注意的一些约束:
- 它可以采用各种形式-用户名、linux 用户 ID、组名称、linux 组 ID、
username:groupname
和其他 ID 变体。 - 没有验证指定的用户或组是否存在于映像上。
- 更改用户可能会更改应用的行为,尤其是在 文件系统 权限等方面。
此字段的默认值因项目 TFM 和目标操作系统而异:
- 如果要面向 .NET 8 或更高版本并使用Microsoft运行时映像,则:
- 在 Linux 上,将使用无根用户
app
(尽管用户 ID 引用了该用户 ID) - 在 Windows 上使用无根用户
ContainerUser
- 在 Linux 上,将使用无根用户
- 否则,不使用默认
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 格式。
有关详细信息,请参阅 在现有标签基础结构上实现传统标签。
另请参阅
- 使用 dotnet 发布 容器化 .NET 应用
- .NET 容器映像