.NET SDK 容器创建概述
虽然可以使用 Dockerfile 容器化 .NET 应用,但使用 .NET SDK 直接容器化应用有令人信服的理由。 本文概述了 .NET SDK 容器创建功能,其中包含与遥测、发布注意事项、生成属性和容器注册表身份验证相关的详细信息。
发布项目注意事项
有了 .NET 应用后,即可将其发布为容器。 在执行此操作之前,需要考虑几个重要注意事项。 在 .NET SDK 版本 8.0.200 之前,需要 📦 Microsoft.NET.Build.Containers NuGet 包。 .NET SDK 版本 8.0.200 及更高版本不需要此包,因为默认情况下包含容器支持。
若要将 .NET 应用发布为容器,需要以下生成属性:
IsPublishable
:设置为true
。 此属性对于可执行项目类型(例如console
、webapp
和worker
)隐式设置为true
。EnableSdkContainerSupport
:当项目类型为控制台应用时设置为true
。
若要显式启用 SDK 容器支持,请考虑以下项目文件片段:
<PropertyGroup>
<IsPublishable>true</IsPublishable>
<EnableSdkContainerSupport>true</EnableSdkContainerSupport>
</PropertyGroup>
发布开关和生成属性
与所有 .NET CLI 命令一样,可以在命令行上指定
/p:PropertyName=Value
-p:PropertyName=Value
-p PropertyName=Value
--property PropertyName=Value
你可以随意使用你喜欢的语法,但文档演示了使用 -p
窗体的示例。
提示
若要帮助进行故障排除,请考虑使用 MSBuid 日志。 若要生成二进制日志(binlog)文件,请将 -bl
开关添加到 dotnet publish
命令。 Binlog 文件可用于诊断生成问题,并且可以在 MSBuild 结构化日志查看器中打开。 它们提供生成过程的详细跟踪,这对于 MSBuild 分析至关重要。 有关详细信息,请参阅 MSBuild故障排除和创建日志。
发布配置文件和目标
使用 dotnet publish
时,使用 -p PublishProfile=DefaultContainer
指定配置文件可以设置一个属性,使 SDK 在发布过程后触发另一个目标。 这是实现所需结果的间接方式。 另一方面,使用 dotnet publish /t:PublishContainer
直接调用 PublishContainer
目标,以更直接的方式实现相同的结果。
换句话说,以下 .NET CLI 命令:
dotnet publish -p PublishProfile=DefaultContainer
将 PublishProfile
属性设置为 DefaultContainer
,等效于以下命令:
dotnet publish /t:PublishContainer
这两种方法之间的区别在于,前者使用配置文件设置属性,而后者直接调用目标。 重要的是,配置文件是 MSBuild 的一项功能,它们可用于以更复杂的方式设置属性,而不仅仅是直接设置属性。
一个关键问题是,并非所有项目类型都支持配置文件或具有相同的配置文件集。 此外,不同工具(如 Visual Studio 和 .NET CLI)对配置文件的支持级别存在差异。 因此,使用目标通常是一种更清晰、更广受支持的方法,可实现相同的结果。
向容器注册表进行身份验证
与专用容器注册表交互需要对这些注册表进行身份验证。
Docker 通过 docker login
命令建立此模式,这是与 Docker 配置文件进行交互的一种方式,该文件包含用于对特定注册表进行身份验证的规则。 微软的 Microsoft.Net.Build.Containers 支持此文件及其所编码的身份验证类型,以用作注册表身份验证。 这将确保该包可以与 docker pull
和 docker push
的任何注册表无缝地协同工作。 此文件通常存储在 ~/.docker/config.json,但可以通过 DOCKER_CONFIG
变量(指向包含 config.json 文件的目录)指定该文件。
身份验证类型
config.json 文件包含三种类型的身份验证:
显式用户名/密码
config.json 文件的 auths
部分是注册表名称和 Base64 编码的 username:password 字符串之间的键/值映射。 在常见的 Docker 方案中,运行 docker login <registry> -u <username> -p <password>
在此映射中创建新项。 这些凭据在持续集成(CI)系统中很受欢迎,其中登录是通过运行开始时的令牌完成的。 然而,由于文件中存在裸凭据的安全风险,它们在最终用户开发计算机上不太受欢迎。
凭据帮助程序
config.json 文件的 credHelpers
部分是注册表名称和特定程序的名称之间的键/值映射,可用于创建和检索该注册表的凭据。 当特定注册表具有复杂的身份验证要求时,通常会使用此功能。 若要使此类身份验证正常工作,必须在系统的 PATH
上具有名为 docker-credential-{name}
的应用程序。 这些类型的凭据往往是安全的,但很难在开发或 CI 计算机上设置。
系统密钥链
credsStore
部分是一个字符串属性,其值是 docker 凭据帮助程序的名称,该程序知道如何与系统的密码管理器进行交互。 例如,对于 Windows,这可能是 wincred
。 这些在 macOS 和 Windows 的 Docker 安装程序中很受欢迎。
通过环境变量进行身份验证
在某些情况下,上述标准 Docker 身份验证机制就是不够用。 此工具具有向注册表提供凭据的其他机制:环境变量。 如果使用环境变量,则不会使用凭据提供机制。 支持以下环境变量:
DOTNET_CONTAINER_REGISTRY_UNAME
:这应该是注册表的用户名。 如果注册表的密码是令牌,则用户名应"<token>"
。DOTNET_CONTAINER_REGISTRY_PWORD
:这应该是注册表的密码或令牌。
注意
自 .NET SDK 8.0.400 起,容器操作的环境变量已更新。 SDK_CONTAINER_*
变量现在以 DOTNET_CONTAINER_*
为前缀。
此机制可能容易受到凭据泄漏的侵害,因此它应仅在其他机制不可用的情况下使用。 例如,如果你 在Docker 容器本身中使用 SDK 容器工具。 此外,该机制没有命名空间功能——它尝试对 源 注册表(您的基础镜像所在的地方)和 目标 注册表(您推送最终镜像的地方)使用相同的凭据。
使用不安全的注册表
大多数注册表访问假定是安全的,这意味着 HTTPS 用于与注册表交互。 但是,并非所有注册表都配置了 TLS 证书,尤其是在 VPN 后面的专用公司注册表等情况下。 为了支持这些用例,容器工具提供了声明特定注册表使用不安全通信的方法。
从 .NET 8.0.400 开始,SDK 了解这些配置文件和格式,并会自动使用该配置来确定是否应使用 HTTP 或 HTTPS。 配置注册表以便进行不安全通信会因所选容器工具而异。
Docker
Docker 将其注册表配置存储在 守护程序配置中。 若要添加新的不安全注册表,需要将新主机添加到 "insecure-registries"
数组属性中:
{
"insecure-registries": [
"registry.mycorp.net"
]
}
注意
必须重启 Docker 守护程序才能对此文件应用任何更改。
Podman
Podman 使用 registries.conf
TOML 文件来存储注册表连接信息。 此文件通常位于 /etc/containers/registries.conf
。 若要添加新不安全的注册表,将添加 TOML 节以保存注册表的设置,然后必须将 insecure
选项设置为 true
。
[[registry]]
location = "registry.mycorp.net"
insecure = true
注意
必须重启 Podman 才能将任何更改应用到 registries.conf 文件。
环境变量
从 9.0.100 开始,.NET SDK 可识别通过 DOTNET_CONTAINER_INSECURE_REGISTRIES
环境变量传递的不安全注册表。 此变量采用逗号分隔的域列表,以与上述 Docker 和 Podman 示例相同的方式视为不安全。
$Env:DOTNET_CONTAINER_INSECURE_REGISTRIES=localhost:5000,registry.mycorp.com; dotnet publish -t:PublishContainer -p:ContainerRegistry=registry.mycorp.com -p:ContainerBaseImage=localhost:5000/dotnet/runtime:9.0
遥测
将 .NET 应用发布为容器时,.NET SDK 容器工具收集并发送有关如何使用这些工具的使用情况遥测数据。 收集的数据是对 .NET CLI发送的
收集的遥测数据本质上是一般情况,不会泄露任何个人信息,目的是帮助衡量:
- 关于 .NET SDK 容器化功能的总体使用情况。
- 成功和失败率,以及有关最频繁发生的故障类型的一般信息。
- 使用技术的特定功能,如发布到各种注册表类型,或调用发布的方式。
若要选择退出遥测,请将 DOTNET_CLI_TELEMETRY_OPTOUT
环境变量设置为 true
。 有关详细信息,请参阅 .NET CLI 遥测。
推理遥测
记录了有关基础映像推理过程如何发生的以下信息:
时间点 | 解释 | 示例值 |
---|---|---|
InferencePerformed |
如果用户手动指定基础映像而不是使用推理。 | true |
TargetFramework |
执行基础映像推理时选择 TargetFramework 。 |
net8.0 |
BaseImage |
选择的基础映像的值,但前提是该基础映像是Microsoft生成的映像之一。 如果用户在 mcr.microsoft.com 上指定Microsoft生成的图像以外的任何图像,则此值为 null。 | mcr.microsoft.com/dotnet/aspnet |
BaseImageTag |
所选标记的值,但前提是该标记属于微软制作的图像之一。 如果用户在 mcr.microsoft.com 上指定Microsoft生成的图像以外的任何图像,则此值为 null。 | 8.0 |
ContainerFamily |
如果用户使用 ContainerFamily 功能选择基础映像中的某个“类型”,则为 ContainerFamily 属性的值。 只有当用户从 mcr.microsoft.com 选择或推测出由 Microsoft 生产的 .NET 映像之一时,才会进行此设置。 |
jammy-chiseled |
ProjectType |
正在被容器化的项目类型。 | AspNetCore 或 Console |
PublishMode |
应用程序是如何打包的。 | Aot 、Trimmed 、SelfContained 或 FrameworkDependent |
IsInvariant |
如果所选映像需要固定全球化,或用户手动选择了此选项。 | true |
TargetRuntime |
发布此应用程序时使用的 RID。 | linux-x64 |
映像创建遥测
下面介绍了如何记录容器创建和发布过程:
时间点 | 解释 | 示例值 |
---|---|---|
RemotePullType |
如果基础映像来自远程注册表,则它是什么样的注册表? | Azure、AWS、Google、GitHub、DockerHub、MRC 或其他 |
LocalPullType |
如果基础映像来自本地源,例如容器守护程序或 tarball。 | Docker、Podman、Tarball |
RemotePushType |
如果映像被推送到远程注册表,则它是什么样的注册表? | Azure、AWS、Google、GitHub、DockerHub、MRC 或其他 |
LocalPushType |
如果映像被推送到本地目标,它是什么? | Docker、Podman、Tarball |
此外,如果在过程中发生各种错误,则收集有关错误类型的数据:
时间点 | 解释 | 示例值 |
---|---|---|
Error |
发生的错误类型 | unknown_repository 、credential_failure 、rid_mismatch 、local_load 。 |
Direction |
如果错误是 credential_failure ,是推送还是拉取注册表? |
push |
目标 RID | 如果错误是 rid_mismatch ,则请求的 RID 是什么 |
linux-x64 |
可用 RID | 如果错误是 rid_mismatch ,则基础映像支持哪些 RID? |
linux-x64,linux-arm64 |