在 Visual Studio 中自定义 Docker 容器

通过编辑你向项目添加 Docker 支持时 Visual Studio 生成的 Dockerfile,可以自定义容器映像。 无论你是从 Visual Studio IDE 生成自定义容器,还是设置命令行生成,都需要了解 Visual Studio 是如何使用 Dockerfile 生成项目的。 你需要了解此类详细信息,因为出于性能方面的考虑,Visual Studio 在生成和运行容器化应用时遵循一个特殊的流程,而这在 Dockerfile 中并不明显。

假设你想要在 Dockerfile 中进行一项更改,并在调试和生产容器中查看结果。 在这种情况下,可以在 Dockerfile 中添加命令来修改第一个阶段(通常为 base)。 请参阅修改容器映像以用于调试和生产。 但是,如果你只想在调试时而不是生产时进行更改,则应创建另一个阶段,并使用 DockerfileFastModeStage 生成设置来告知 Visual Studio 将该阶段用于调试生成。 请参阅修改容器映像以仅用于调试

本文详细介绍了 Visual Studio 的容器化应用生成过程,然后介绍了有关如何修改 Dockerfile 以同时影响调试和生产生成或仅影响调试的信息。

Visual Studio 中的 Dockerfile 生成

注意

本部分介绍在你选择 Dockerfile 容器生成类型时 Visual Studio 使用的容器生成过程。 如果使用 .NET SDK 生成类型,自定义选项会有所不同,并且本部分中的信息不适用。 请改为参阅使用 dotnet publish 容器化 .NET 应用,并使用自定义容器中所述的属性来配置容器生成过程。

多阶段生成

Visual Studio 生成不使用 Docker 容器的项目时,它会在本地计算机上调用 MSBuild,并在本地解决方案文件夹下的文件夹(通常为 bin)中生成输出文件。 但是,对于容器化项目,生成过程会考虑有关生成容器化应用的 Dockerfile 说明。 Visual Studio 使用的 Dockerfile 分为多个阶段。 此过程依赖 Docker 的多阶段生成功能。

多阶段生成功能有助于使容器的生成过程更高效,并使容器更小,方法是让容器仅包含应用在运行时需要的位。 多阶段生成用于 .NET Core 项目,而不用于 .NET Framework 项目。

使用多阶段生成功能,可以在生成中间映像的阶段创建容器映像。 例如,考虑一个典型的 Dockerfile。 第一个阶段在 Visual Studio 生成的 Dockerfile 中称为 base,尽管这些工具并不需要该名称。

# This stage is used when running from VS in fast mode (Default for Debug configuration)
FROM mcr.microsoft.com/dotnet/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

Dockerfile 中的行以 Microsoft Container Registry (mcr.microsoft.com) 中的 ASP.NET 映像开头,创建可公开端口 80 和 443 的中间映像 base,并将工作目录设置为 /app

下一阶段是 build,其显示如下:

# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:3.1-buster-slim AS build
WORKDIR /src
COPY ["WebApplication43/WebApplication43.csproj", "WebApplication43/"]
RUN dotnet restore "WebApplication43/WebApplication43.csproj"
COPY . .
WORKDIR "/src/WebApplication43"
RUN dotnet build "WebApplication43.csproj" -c Release -o /app/build

你可以看到,build 阶段是从注册表(sdk 而不是 aspnet)中的其他原始映像开始,而不是从基础映像继续。 sdk 映像包含所有生成工具,因此,它比仅包含运行时组件的 aspnet 映像大得多。 如果看看 Dockerfile 的其余部分,你就会清楚使用单独映像的原因:

# This stage is used to publish the service project to be copied to the final stage
FROM build AS publish
RUN dotnet publish "WebApplication43.csproj" -c Release -o /app/publish

# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication43.dll"]

最后阶段再次从 base 开始,并包括 COPY --from=publish 以将发布的输出复制到最终映像中。 由于无需包含 sdk 映像中的所有生成工具,因此此过程可以使最终映像小得多。

下表总结了 Visual Studio 创建的典型 Dockerfile 中使用的阶段:

阶段 说明
base 创建发布生成应用所在的基本运行时映像。 运行时需要可用的设置(例如端口和环境变量)都在此处。 在快速模式下从 VS 运行时使用此阶段(调试配置的默认值)。
build 该项目在此阶段生成。 使用 .NET SDK 基础映像,该映像具有生成项目所需的组件。
发布... 此阶段派生自生成阶段并发布项目,该项目将复制到最终阶段。
final 此阶段配置了如何启动应用,并在生产环境中或在常规模式下从 VS 运行时使用(不使用调试配置时的默认值)。
aotdebug 从 VS 启动时,此阶段用作最终阶段的基础,以支持在常规模式下进行调试(不使用调试配置时的默认值)。

注意

仅 Linux 容器支持该 aotdebug 阶段。 如果在项目上启用了 本机预先 (AOT) 部署,则会在 Visual Studio 2022 17.11 及更高版本中使用它。

项目预热

项目预热指的是在为项目选择 Docker 配置文件时(即在加载项目或添加 Docker 支持时)执行的一系列步骤,旨在提高后续运行的性能(F5Ctrl+F5)。 在工具>选项>容器工具下可以配置此行为。 下面是在后台运行的任务:

  • 检查 Docker Desktop 是否已安装且正在运行。
  • 确保将 Docker Desktop 设置为与项目相同的操作系统。
  • 在 Dockerfile 的第一阶段(大部分 Dockerfile 中的 base 阶段)拉取映像。
  • 生成 Dockerfile 并启动容器。

预热仅在“快速”模式下发生,因此正在运行的容器对 app 文件夹进行卷装载。 这意味着对应用所做的任何更改都不会使容器无效。 此行为可以大幅提升调试性能,并缩短长期任务(例如拉取大型映像)的等待时间。

启用详细的容器工具日志

出于诊断目的,可以启用某些容器工具日志。 可以通过设置某些环境变量来启用这些日志。 对于单个容器项目,环境变量为 MS_VS_CONTAINERS_TOOLS_LOGGING_ENABLED,随后会记录到 %tmp%\Microsoft.VisualStudio.Containers.Tools 中。 对于 Docker Compose 项目,环境变量为 MS_VS_DOCKER_TOOLS_LOGGING_ENABLED,随后会记录在 %tmp%\Microsoft.VisualStudio.DockerCompose.Tools 中。

警告

启用日志记录并使用令牌代理进行 Azure 身份验证时,身份验证凭据可以记录为纯文本。 请参阅配置 Azure 身份验证

后续步骤

了解如何使用 Dockerfile 阶段自定义用于调试和生产的映像,例如,仅当调试时如何在映像上安装工具。 请参阅配置容器映像进行调试