Share via


Customize containers in Visual Studio

You can customize your container images by editing the Dockerfile that Visual Studio generates when you add container support to your project. Whether you're building a customized container from the Visual Studio IDE, or setting up a command-line build, you need to know how Visual Studio uses the Dockerfile to build your projects. You need to know such details because, for performance reasons, Visual Studio follows a special process for building and running containerized apps that isn't obvious from the Dockerfile.

This article explains the Visual Studio build process for containerized apps in some detail, then it contains information on how to modify the Dockerfile to affect both debugging and production builds, or just for debugging.

Dockerfile builds in Visual Studio

Multistage build

When Visual Studio builds a project that doesn't use Docker containers, it invokes MSBuild on the local machine and generates the output files in a folder (typically bin) under your local solution folder. For a containerized project, however, the build process takes account of the Dockerfile's instructions for building the containerized app. The Dockerfile that Visual Studio uses is divided into multiple stages. This process relies on Docker's multistage build feature.

The multistage build feature helps make the process of building containers more efficient, and makes containers smaller by allowing them to contain only the bits that your app needs at run time.

The multistage build allows container images to be created in stages that produce intermediate images. As an example, consider a typical Dockerfile. The first stage is called base in the Dockerfile that Visual Studio generates, although the tools don't require that name.

The next stage is build, which appears as follows:

# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:8.0 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

You can see that the build stage starts from a different original image from the registry (sdk rather than aspnet), rather than continuing from base. The sdk image has all the build tools, and for that reason it's a lot bigger than the aspnet image, which only contains runtime components. The reason for using a separate image becomes clear when you look at the rest of the 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"]

The final stage starts again from base, and includes the COPY --from=publish to copy the published output to the final image. This process makes it possible for the final image to be a lot smaller, since it doesn't need to include all of the build tools that were in the sdk image.

The following table summarizes the stages used in the typical Dockerfile created by Visual Studio:

Project warmup

Project warmup refers to a series of steps that happen when the Container profile is selected for a project (that is, when a project is loaded or container support is added) in order to improve the performance of subsequent runs (F5 or Ctrl+F5).

Warmup only happens in Fast mode, so the running container has the app folder volume-mounted. That means that any changes to the app don't invalidate the container. This behavior improves the debugging performance significantly and decreases the wait time for long running tasks such as pulling large images.

Enable detailed container tools logs

For diagnostic purposes, you can enable certain Container Tools logs. You can enable these logs by setting certain environment variables. For single container projects, the environment variable is MS_VS_CONTAINERS_TOOLS_LOGGING_ENABLED, which then logs in %tmp%\Microsoft.VisualStudio.Containers.Tools. For Docker Compose projects, the variable is MS_VS_DOCKER_TOOLS_LOGGING_ENABLED, which then logs in %tmp%\Microsoft.VisualStudio.DockerCompose.Tools.

Next steps

Learn about how to use the Dockerfile stages to customize the images used for debugging and production, for example, how to install a tool on the image only when debugging. See Configure container images for debugging.