Настройка контейнеров Docker в Visual Studio

Вы можете настроить образы контейнеров, отредактировав файл Dockerfile, который Visual Studio создает при включении поддержки Docker в проекте. Независимо от того, выполняете ли вы сборку настраиваемого контейнера из интегрированной среды разработки Visual Studio или настраиваете сборку из командной строки, необходимо знать, как в Visual Studio используется файл Dockerfile для сборки проектов. Вам необходимо это знать, так как по соображениям производительности Visual Studio следует специальному процессу создания и запуска контейнерных приложений, который не очевиден из Dockerfile.

Предположим, вы хотите внести изменения в Dockerfile и увидеть результаты отладки и рабочих контейнеров. В этом случае можно добавить команды в Dockerfile, чтобы изменить первый этап (обычно base). См. раздел Изменение образа контейнера для среды отладки и рабочей среды. Но если вы хотите внести изменения только для среды отладки, но не рабочей среды, вам следует создать еще один этап и использовать параметр сборки DockerfileFastModeStage, чтобы указать Visual Studio использовать этот этап для отладочных сборок. См. раздел Изменение образа контейнера только для среды отладки.

В этой статье подробно описан процесс сборки Visual Studio для контейнерных приложений, а также показано, как изменить файл Dockerfile, чтобы он повлиял как на сборки отладки, так и на рабочие сборки, или только на сборки отладки.

Сборки Dockerfile в Visual Studio

Примечание.

В этом разделе описывается процесс сборки контейнера, который Visual Studio использует при выборе типа сборки контейнера Dockerfile. Если вы используете тип сборки пакета SDK для .NET, параметры настройки отличаются, а сведения в этом разделе не применимы. Вместо этого см. раздел "Контейнеризация приложения .NET с помощью dotnet publish " и использование свойств, описанных в статье "Настройка контейнера" для настройки процесса сборки контейнера .

Многоэтапная сборка

Когда в Visual Studio выполняется сборка проекта, который не использует контейнеры Docker, на локальном компьютере вызывается MSBuild и создаются выходные файлы в папке (обычно bin), вложенной в локальную папку решения. Однако для контейнерного проекта в процессе сборки учитываются инструкции из файла Dockerfile. Сборка с помощью Dockerfile в Visual Studio делится на несколько этапов. При этом применяется функция многоэтапной сборки Docker.

Функция многоэтапной сборки повышает эффективность сборки контейнеров и позволяет уменьшить их размер, так как они содержат только тот код, который требуется приложению во время выполнения. Многоэтапная сборка применяется для проектов .NET Core, но не для проектов .NET Framework.

При многоэтапной сборке образы контейнеров создаются в несколько шагов, на каждом из которых формируются промежуточные образы. В качестве примера рассмотрим обычный объект Dockerfile. Первый этап называется base в файле Dockerfile, создаваемом Visual Studio, хотя для инструментов это имя не требуется.

FROM mcr.microsoft.com/dotnet/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

Сначала в Dockerfile используется образ ASP.NET из реестра контейнеров Майкрософт (mcr.microsoft.com) для создания промежуточного образа base, для которого открываются порты 80 и 443, и определения рабочей папки /app.

Следующий этап — build. Выглядит он так:

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 вместо продолжения работы с образом base берется другой исходный образ из реестра (sdk, а не aspnet). Образ sdk содержит все средства сборки и поэтому гораздо больше, чем образ aspnet, который содержит только компоненты времени выполнения. Причина использования отдельного образа становится очевидной, если посмотреть на остальную часть файла Dockerfile:

FROM build AS publish
RUN dotnet publish "WebApplication43.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication43.dll"]

Последний этап снова начинается с образа base и включает в себя команду COPY --from=publish, которая копирует опубликованные выходные данные в итоговый образ. Это позволяет значительно уменьшить итоговый образ, так как в него не нужно включать все средства сборки, которые имелись в образе sdk.

MSBuild

Примечание.

В этом разделе описывается, как настроить контейнеры Docker при выборе типа сборки контейнера Dockerfile. Если вы используете тип сборки пакета SDK для .NET, параметры настройки отличаются, а сведения в этой статье не применимы. Вместо этого см. раздел "Контейнеризация приложения .NET с помощью dotnet publish".

Dockerfiles, созданные Visual Studio для проектов платформа .NET Framework (и для проектов .NET Core, созданных с использованием версий Visual Studio до Visual Studio 2017 с обновлением 4), не являются многоэтапными файлами Dockerfile. Действия, описанные в этих файлах Dockerfile, не компилируют код. Вместо этого, когда среда Visual Studio выполняет сборку с помощью Dockerfile для .NET Framework, она сначала компилирует проект с помощью MSBuild. Если компиляция завершилась успешно, Visual Studio выполняет сборку Dockerfile. При этом выходные данные сборки из MSBuild просто копируются в полученный образ Docker. Так как инструкции по компиляции кода не включаются в Dockerfile, выполнять сборку файлов Dockerfile для .NET Framework с помощью команды docker build из командной строки невозможно. Для сборки таких проектов следует использовать MSBuild.

Чтобы создать образ для одного проекта контейнера Docker, можно использовать MSBuild с параметром /t:ContainerBuild команды. Эта команда сообщает MSBuild создать целевой объект ContainerBuild , а не целевой объект Buildпо умолчанию. Например:

MSBuild MyProject.csproj /t:ContainerBuild /p:Configuration=Release

При сборке решения из интегрированной среды разработки Visual Studio отображаются выходные данные, аналогичные тому, что отображается в окне вывода . Всегда используйте /p:Configuration=Release, так как при применении оптимизации многоэтапной сборки в Visual Studio результаты сборки в конфигурации отладки могут отличаться от ожидаемых. См. раздел Отладка.

Если вы используете проект Docker Compose, используйте эту команду для создания образов:

msbuild /p:SolutionPath=<solution-name>.sln /p:Configuration=Release docker-compose.dcproj

Отладка

Примечание.

В этом разделе описывается, как настроить контейнеры Docker при выборе типа сборки контейнера Dockerfile. Если вы используете тип сборки пакета SDK для .NET, параметры настройки отличаются, и большинство сведений в этом разделе неприменимо. Вместо этого см. раздел "Контейнеризация приложения .NET с помощью dotnet publish".

При сборке в конфигурации отладки существует несколько оптимизаций, которые Visual Studio помогает с производительностью процесса сборки для контейнерных проектов. Процесс сборки для контейнерных приложений не так прост, как просто после выполнения шагов, описанных в Dockerfile. Сборка в контейнере медленнее, чем сборка на локальном компьютере. Поэтому при сборке в конфигурации отладки Visual Studio на самом деле выполняет сборку проектов на локальном компьютере, а затем предоставляет доступ к папке с выходными данными контейнеру путем подключения к тому. Сборка с такой оптимизацией называется сборкой в быстром режиме.

В быстром режиме Visual Studio вызывается docker build с аргументом, который сообщает Docker создать только первый этап в Dockerfile (обычно этап base ). Это можно изменить, задав свойство MSBuild, DockerfileFastModeStageописанное в свойствах MSBuild для контейнеров. Остальные этапы процесса выполняет сама среда Visual Studio с учетом содержимого Dockerfile. Поэтому, когда вы изменяете файл Dockerfile, например для настройки среды контейнера или установки дополнительных зависимостей, изменения должны вноситься на первом этапе. Любые пользовательские шаги, размещенные в dockerfile build, publishили final этапы не выполняются.

Данная оптимизация производительности применяется только при сборке в конфигурации отладки. В конфигурации выпуска сборка выполняется в контейнере, как указано в Dockerfile.

Чтобы отключить оптимизацию производительности и выполнить сборку, как указано в Dockerfile, присвойте свойству ContainerDevelopmentMode значение Regular в файле проекта следующим образом:

<PropertyGroup>
   <ContainerDevelopmentMode>Regular</ContainerDevelopmentMode>
</PropertyGroup>

Чтобы снова включить оптимизацию производительности, удалите это свойство из файла проекта.

При запуске отладки (F5) используется ранее запущенный контейнер, если это возможно. Если вы не хотите повторно использовать имеющийся контейнер, можно выбрать в Visual Studio команду Перестроить или Очистить, чтобы использовался новый контейнер.

Процесс запуска отладчика зависит от типа проекта и операционной системы контейнера:

Сценарий Процесс отладчика
Приложения .NET Core (контейнеры Linux) Visual Studio скачивает vsdbg и сопоставляет его с контейнером. Затем он вызывается в программе с соответствующими аргументами (dotnet webapp.dll), после чего к процессу привязывается отладчик.
Приложения .NET Core (контейнеры Windows) Visual Studio использует onecoremsvsmon и сопоставляет его с контейнером. После этого он запускается в качестве точки входа, а затем Visual Studio устанавливает подключение к нему и привязывает его к программе. Этот процесс аналогичен типовой настройке удаленной отладки на другом компьютере или виртуальной машине.
Приложения .NET Framework Visual Studio использует msvsmon и сопоставляет его с контейнером. После этого он запускается в составе точки входа, где Visual Studio может установить подключение к нему и привязать его к программе.

Дополнительные сведения см. в vsdbg.exeстатье Об отладке .NET Core в Linux и OS X из Visual Studio.

Изменение образа контейнера для среды отладки и рабочей среды

Чтобы изменить образ контейнера для среды отладки и рабочей среды, измените этап base. Добавьте настройки в Dockerfile в раздел базового этапа; как правило, это первый раздел в Dockerfile. Дополнительные сведения о командах Dockerfile см. в разделе Справочник по Dockerfile в документации по Dockerfile.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# <add your commands here>

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["WebApplication3/WebApplication3.csproj", "WebApplication3/"]
RUN dotnet restore "WebApplication3/WebApplication3.csproj"
COPY . .
WORKDIR "/src/WebApplication3"
RUN dotnet build "WebApplication3.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WebApplication3.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication3.dll"]

Изменение образа контейнера только для среды отладки

Этот сценарий применяется, когда вы хотите сделать что-то со своими контейнерами для отладки, например, установить что-то для диагностических целей, но вы не хотите, чтобы это устанавливалось в рабочих сборках.

Чтобы изменить контейнер только для отладки, создайте этап, а затем используйте свойство DockerfileFastModeStage MSBuild, чтобы указать Visual Studio использовать настроенный этап при отладке. Дополнительные сведения о командах Dockerfile см. в разделе Справочник по Dockerfile в документации по Dockerfile.

В следующем примере мы устанавливаем пакет procps-ng, но только в режиме отладки. Этот пакет предоставляет команду pidof, требуемую Visual Studio, но не используется в образе Mariner, используемом здесь. Этап, который мы используем для отладки в быстром режиме, — это debug, пользовательский этап, определенный здесь. Этап быстрого режима не должен наследоваться от этапа или publish наследовать его непосредственно от buildbase этапа, так как Visual Studio подключает том, содержащий все необходимое для запуска приложения, как описано ранее в этой статье.

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0-cbl-mariner2.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM base AS debug
RUN tdnf install procps-ng -y

FROM mcr.microsoft.com/dotnet/sdk:6.0-cbl-mariner2.0 AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

В файле проекта добавьте этот параметр, чтобы указать Visual Studio использовать ваш пользовательский этап debug при отладке.

  <PropertyGroup>
     <!-- other property settings -->
     <DockerfileFastModeStage>debug</DockerfileFastModeStage>
  </PropertyGroup>

В следующих разделах содержатся сведения, которые могут оказаться полезными в некоторых случаях, например, если требуется указать другую точку входа, или если приложение включено SSL, и вы изменяете что-то, что может повлиять на способ обработки SSL-сертификатов.

Сборка из командной строки

Если вы хотите создать проект контейнера с dockerfile за пределами Visual Studio, можно использовать docker build, MSBuilddotnet buildили dotnet publish создать из командной строки.

Если вы используете тип сборки пакета SDK для .NET, у вас нет файла Dockerfile, поэтому вместо этого вы не можете использовать ; вместо этого используйте docker buildMSBuilddotnet build или dotnet publish выполните сборку в командной строке.

Использование сборки Docker

Для сборки контейнерного решения из командной строки обычно можно использовать команду docker build <context> для каждого проекта в решении. Укажите аргумент build context. build context для Dockerfile — это папка на локальном компьютере, которая служит рабочей папкой для создания образа. Например, из нее копируются файлы в контейнер. Для проектов .NET Core используйте папку, содержащую файл решения (SLN). При использовании относительного пути этот аргумент обычно имеет значение ".." для Dockerfile в папке проекта и файла решения в родительской папке. Для проектов .NET Framework контекст сборки — это папка проекта, а не решения.

docker build -f Dockerfile ..

Прогрев проекта

Под прогревом проекта понимается последовательность действий, которая выполняется при выборе профиля Docker для проекта (то есть при загрузке проекта или добавлении поддержки Docker) с целью оптимизировать его производительность при последующих запусках (F5 или CTRL+F5). Это поведение можно настроить в разделе "Средства> параметров>контейнера". Ниже описываются задачи, которые выполняются в фоновом режиме:

  • Проверка установки и запуска Docker Desktop.
  • Проверка того, что для Docker Desktop и проекта задана одна и та же операционная система.
  • Извлечение образа на первом этапе файла Dockerfile (этап base в большинстве файлов Dockerfile).
  • Создание файла Dockerfile и запуск контейнера.

Прогревание происходит только в быстром режиме, поэтому запущенный контейнер подключен к папке приложения . Это означает, что любые изменения в приложении не делают контейнер недействительным. Это поведение значительно повышает производительность отладки и уменьшает время ожидания длительных задач, таких как извлечение больших образов.

Сопоставление томов

Чтобы реализовать отладку в контейнерах, Visual Studio использует сопоставление томов для сопоставления отладчика и папок NuGet с хост-компьютера. Сопоставление томов описано в документации по Docker. Сопоставления томов для контейнера можно просмотреть с помощью окна "Контейнеры" в Visual Studio.

Ниже перечислены тома, которые подключаются в контейнере:

Громкость Description
Папка приложения Содержит папку проекта, в которой располагается файл Dockerfile.
Папки пакетов NuGet Содержит пакеты NuGet и резервные папки, которые считываются из файла obj{project}.csproj.nuget.g.props в проекте.
Удаленный отладчик Содержит компоненты, необходимые для запуска отладчика в контейнере, в соответствии с типом проекта. См. раздел "Отладка".
Исходная папка Содержит контекст сборки, который передается в команды Docker.

Ниже приведены тома, подключенные в контейнере. Отображаемые в контейнерах значения могут отличаться в зависимости от используемой дополнительной версии Visual Studio 2022.

Громкость Description
Папка приложения Содержит папку проекта, в которой располагается файл Dockerfile.
HotReloadAgent Содержит файлы для агента горячей перезагрузки.
HotReloadProxy Содержит файлы, необходимые для запуска службы, которая позволяет агенту перезагрузки узла взаимодействовать с Visual Studio на узле.
Папки пакетов NuGet Содержит пакеты NuGet и резервные папки, которые считываются из файла obj{project}.csproj.nuget.g.props в проекте.
Удаленный отладчик Содержит компоненты, необходимые для запуска отладчика в контейнере, в соответствии с типом проекта. Это объясняется более подробно в разделе Отладка.
Исходная папка Содержит контекст сборки, который передается в команды Docker.
TokenService.Proxy Содержит файлы, необходимые для запуска службы, которая позволяет VisualStudioCredential взаимодействовать с Visual Studio на узле.

Для .NET 8 дополнительные точки подключения в корневом каталоге и для пользователя приложения, содержащего секреты пользователя и сертификат HTTPS, также могут присутствовать. И в предварительной версии Visual Studio 17.10 том службы Горячая перезагрузка и маркеров, а также другой компонент, вспомогательный компонент, объединяются в одну точку /VSToolsподключения.

Примечание.

Предварительная версия Visual Studio 17.10 Если вы используете подсистему Docker в подсистема Windows для Linux (WSL) без Docker Desktop, задайте для переменной VSCT_WslDaemon=1 среды путь Visual Studio использовать пути WSL при создании подключений томов. Пакет NuGet Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.20.0-Preview 1 также требуется.

В веб-приложениях ASP.NET Core могут использоваться две дополнительные папки для SSL-сертификата и секретных ключей пользователей, которые более подробно описываются в следующем разделе.

Включение подробных журналов средств контейнера

В целях диагностики можно включить определенные журналы средств контейнеров. Эти журналы можно включить, задав определенные переменные среды. Для проектов одного контейнера переменная среды — это MS_VS_CONTAINERS_TOOLS_LOGGING_ENABLEDпеременная среды, которая затем входит в %tmp%\Microsoft.VisualStudio.Containers.Toolsсистему. Для проектов %tmp%\Microsoft.VisualStudio.DockerCompose.ToolsDocker Compose это MS_VS_DOCKER_TOOLS_LOGGING_ENABLEDзначит, что затем выполняет вход.

Внимание

Если ведение журнала включено и вы используете прокси-сервер маркера для проверки подлинности Azure, учетные данные проверки подлинности могут быть записаны как обычный текст. См. статью "Настройка проверки подлинности Azure".

Точка входа контейнера

Visual Studio использует подходящую точку входа контейнера в зависимости от типа проекта и операционной системы контейнера. Ниже описываются возможные комбинации:

Тип контейнера Точка входа
Контейнеры Linux В качестве точки входа используется tail -f /dev/null, представляющая собой бесконечный цикл ожидания, в рамках которого обеспечивается выполнение контейнера. Когда приложение запускается через отладчик, это отладчик, который отвечает за запуск приложения (т dotnet webapp.dll. е. ). При запуске без отладки инструментарий выполняет docker exec -i {containerId} dotnet webapp.dll для запуска приложения.
Контейнеры Windows Точка входа — это то, что C:\remote_debugger\x64\msvsmon.exe /noauth /anyuser /silent /nostatus запускает отладчик, поэтому он прослушивает подключения. Этот метод применяется, когда отладчик запускает приложение. При запуске без отладки используется команда docker exec. Для веб-приложений .NET Framework точка входа несколько отличается: к команде добавляется ServiceMonitor.

Точка входа контейнера может быть изменена только в проектах Docker Compose, а не в проектах с одним контейнером.

Приложения ASP.NET Core с поддержкой SSL

Инструменты для контейнеров в Visual Studio поддерживают отладку в приложениях ASP.NET Core с поддержкой SSL с использованием сертификата разработки так же, как и при работе без контейнеров. Для этого Visual Studio выполняет несколько дополнительных действий для экспорта сертификата и предоставления контейнеру доступа к нему. Ниже приведена процедура, выполняемая средой Visual Studio при отладке в контейнере.

  1. С помощью средства dev-certs проверяется наличие доверенного сертификата разработки на хост-компьютере.

  2. Экспортирует сертификат %APPDATA%\ASP.NET\Https в безопасный пароль, хранящийся в хранилище секретов пользователя для этого конкретного приложения.

  3. Том подключает следующие каталоги:

    • *%APPDATA%\Microsoft\UserSecrets
    • *%APPDATA%\ASP.NET\Https

ASP.NET Core ищет сертификат, соответствующий имени сборки в папке Https , поэтому он сопоставляется с контейнером в этом пути. Путь к сертификату и пароль также можно определить с помощью переменных среды (ASPNETCORE_Kestrel__Certificates__Default__Path и ASPNETCORE_Kestrel__Certificates__Default__Password) или в JSON-файле секретных ключей пользователей, например следующим образом:

{
  "Kestrel": {
    "Certificates": {
      "Default": {
        "Path": "c:\\app\\mycert.pfx",
        "Password": "strongpassword"
      }
    }
  }
}

Если конфигурация поддерживает как контейнерные, так и неконтейнерные сборки, следует использовать переменные среды, так как пути зависят от среды контейнеров.

Дополнительные сведения о поддержке SSL в приложениях ASP.NET Core в контейнерах см. в разделе Размещение образов ASP.NET Core с Docker через HTTPS.

Пример кода, демонстрирующий создание пользовательских сертификатов для многослужбного приложения, доверенного на узле и в контейнерах для обмена данными между службами HTTPS, см. в разделе CertExample.