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 ビルド

Note

このセクションでは、Dockerfile コンテナーのビルドの種類を選んだときに Visual Studio が実行するコンテナーのビルド プロセスについて説明します。 .NET SDK のビルドの種類を使う場合は異なるカスタマイズ オプションになるため、このセクションの情報は適用できません。 代わりに、「dotnet publish を使用して .NET アプリをコンテナー化する」を参照し、「コンテナーをカスタマイズする」で説明されているプロパティを使って、コンテナーのビルド プロセスを構成してください。

マルチステージ ビルド

Visual Studio では、Docker コンテナーを使用しないプロジェクトをビルドするときに、ローカル コンピューター上で MSBuild が呼び出され、ローカル ソリューション フォルダーの下のフォルダー (通常は bin) 内に出力ファイルが生成されます。 ただし、コンテナー化されたプロジェクトの場合、コンテナー化されたアプリをビルドするため、ビルド プロセスで Dockerfile の命令が考慮されます。 Visual Studio で使用される Dockerfile は、複数のステージに分割されます。 このプロセスは、Docker のマルチステージ ビルド機能に依存しています。

マルチステージ ビルド機能を使用すると、コンテナーのビルド プロセスが効率化され、実行時にアプリに必要なビットしか含めないようにすることで、コンテナーのサイズを小さくすることができます。 マルチステージ ビルドは、.NET Framework プロジェクトではなく、.NET Core プロジェクトに使用されます。

マルチステージ ビルドを使用すると、中間イメージを生成するステージでコンテナー イメージを作成できます。 たとえば、次のような一般的な Dockerfile があるとします。 最初のステージは、Visual Studio によって生成される Dockerfile では base と呼ばれますが、ツールではその名前は必要ありません。

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 で、次のように表示されます。

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 からの続きではなく、レジストリ (aspnet ではなく sdk) からの別の、元のイメージから開始されることがわかります。 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

Note

このセクションでは、Dockerfile コンテナーのビルドの種類を選ぶ場合に Docker コンテナーをカスタマイズする方法について説明します。 .NET SDK のビルドの種類を使う場合は異なるカスタマイズ オプションになるため、この記事の情報は適用できません。 代わりに、「dotnet publish を使用して .NET アプリをコンテナー化する」を参照してください。

Visual Studio によって .NET Framework プロジェクト用 (および Visual Studio 2017 Update 4 より前のバージョンの Visual Studio で作成された .NET Core プロジェクト用) に作成された Dockerfile は、マルチステージの Dockerfile ではありません。 これらの Dockerfile のステップでは、コードはコンパイルされません。 代わりに、Visual Studio では .NET Framework Dockerfile をビルドする際に、まず MSBuild を使用してプロジェクトがコンパイルされます。 これが成功すると、Visual Studio によって Dockerfile がビルドされます。これは単純に、MSBuild からのビルド出力が、生成された Docker イメージにコピーされます。 コードをコンパイルするステップは Dockerfile に含まれていないため、コマンド ラインから docker build を使用して .NET Framework Dockerfile をビルドすることはできません。 これらのプロジェクトをビルドするには、MSBuild を使用する必要があります。

単一の Docker コンテナー プロジェクトのイメージをビルドするには、MSBuild を /t:ContainerBuild コマンド オプションと共に使います。 このコマンドは、既定のターゲット Build ではなく、ターゲット ContainerBuild をビルドするように MSBuild に指示します。 次に例を示します。

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

Visual Studio IDE からソリューションをビルドすると、出力ウィンドウに表示されるものと同様の出力が表示されます。 Visual Studio でマルチステージ ビルドの最適化が使用されている場合は、デバッグ構成をビルドするときに得られる結果が想定どおりでない場合があるため、常に /p:Configuration=Release を使用します。 「デバッグ」を参照してください。

Docker Compose プロジェクトを使っている場合は、次のコマンドを使ってイメージをビルドします。

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

デバッグ

Note

このセクションでは、Dockerfile コンテナーのビルドの種類を選ぶ場合に Docker コンテナーをカスタマイズする方法について説明します。 .NET SDK のビルドの種類を使う場合は異なるカスタマイズ オプションになるため、このセクションの情報のほとんどは適用できません。 代わりに、「dotnet publish を使用して .NET アプリをコンテナー化する」を参照してください。

[デバッグ] 構成でビルドする場合、コンテナー化されたプロジェクトのビルド プロセスのパフォーマンス向上に役立つ Visual Studio の最適化がいくつかあります。 コンテナー化されたアプリのビルド プロセスは、単に Dockerfile に記載されている手順に従うほど単純ではありません。 コンテナーでのビルドは、ローカル コンピューターでのビルドよりも低速です。 そのため、デバッグ構成でビルドすると、Visual Studio によって実際にプロジェクトがローカル コンピューター上にビルドされてから、ボリューム マウントを使用して出力フォルダーがコンテナーに共有されます。 この最適化が有効になっているビルドは、高速モードのビルドと呼ばれます。

高速モードでは、Visual Studio は引数を指定して docker build を呼び出し、Dockerfile の最初のステージ (通常は base ステージ) のみをビルドするよう Docker に指示します。 これを変更するには、コンテナー ツールの MSBuild プロパティに関する記事で説明されている MSBuild プロパティ DockerfileFastModeStage を設定します。 Visual Studio では、Dockerfile の内容に関係なく、プロセスの残りの部分が処理されます。 そのため、コンテナー環境をカスタマイズしたり、追加の依存関係をインストールしたりするために Dockerfile を変更する場合は、最初のステージで変更を加える必要があります。 Dockerfile の buildpublish、または final ステージに配置されたカスタム ステップは実行されません。

このパフォーマンスの最適化は、デバッグ構成でビルドする場合にのみ発生します。 リリース構成では、Dockerfile で指定されているように、コンテナーでビルドが実行されます。

Dockerfile によって指定されているパフォーマンスの最適化とビルドを無効にする場合は、次のように、プロジェクト ファイルの ContainerDevelopmentMode プロパティを Regular に設定します。

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

パフォーマンスの最適化を復元するには、プロジェクト ファイルからプロパティを削除します。

デバッグを開始すると (F5 キー)、可能であれば、以前に開始したコンテナーが再利用されます。 前のコンテナーを再利用しない場合は、Visual Studio で Rebuild または Clean コマンドを使用して、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 の詳細については、「Visual Studio からの Linux および OS X 上の .NET Core のオフロード デバッグ」をご覧ください。

デバッグと運用のためにコンテナー イメージを変更する

デバッグと運用の両方用にコンテナー イメージを変更するには、base ステージを変更します。 カスタマイズを基本ステージ セクション (通常は Dockerfile の最初のセクション) の Dockerfile に追加します。 Dockerfile コマンドの詳細については、Docker ドキュメントの「Dockerfile reference (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"]

デバッグ用にのみコンテナー イメージを変更する

このシナリオは、診断目的で何かをインストールするなど、デバッグ プロセスで役立つ何かをコンテナーを使って実行したいが、運用環境のビルドにはインストールしたくない場合に適しています。

デバッグ用にのみコンテナーを変更するには、ステージを作成してから、MSBuild プロパティ DockerfileFastModeStage を使用して、デバッグ時にカスタマイズしたステージを使用するように Visual Studio に指示します。 Dockerfile コマンドの詳細については、Docker ドキュメントの「Dockerfile reference (Dockerfile リファレンス)」を参照してください。

次の例では、パッケージ procps-ng をデバッグ モードでのみインストールします。 このパッケージはコマンド pidof を提供します。これは Visual Studio に必要ですが、ここで使われている Mariner イメージには含まれていません。 高速モードのデバッグ用に使用するステージは debug です (ここで定義されているカスタム ステージ)。 高速モード ステージは build または publish ステージから継承する必要はありません。この記事で前述したように、Visual Studio はアプリの実行に必要なすべてのものを含むボリュームをマウントするため、base ステージから直接継承できます。

#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"]

プロジェクト ファイルで、この設定を追加して、デバッグ時にカスタム ステージ debug を使用するように Visual Studio に指示します。

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

次のセクションでは、別のエントリ ポイントを指定する場合や、アプリが SSL 対応で、SSL 証明書の処理方法に影響を与える可能性のある変更を行う場合など、特定のケースで役立つ可能性のある情報を示します。

コマンド ラインからのビルド

Visual Studio 外で Dockerfile を使ってコンテナー プロジェクトをビルドする場合は、docker buildMSBuilddotnet build、または dotnet publish を使ってコマンド ラインからビルドできます。

.NET SDK のビルドの種類を使う場合は、Dockerfile がないため、docker build を使うことはできません。代わりに MSBuilddotnet build、または dotnet publish を使ってコマンド ラインでビルドしてください。

docker build を使う

コマンド ラインからコンテナー化されたソリューションをビルドするには、通常、ソリューション内の各プロジェクトに対してコマンド docker build <context> を使用します。 build context 引数を指定します。 Dockerfile の build context は、イメージを生成する作業フォルダーとして使用されるローカル コンピューター上のフォルダーです。 たとえば、コンテナーにコピーするときにファイルをコピーするフォルダーです。 .NET Core プロジェクトでは、ソリューション ファイル (.sln) が格納されているフォルダーを使用します。 相対パスとして表されます。この引数は、通常、プロジェクト フォルダー内の Dockerfile とその親フォルダー内のソリューション ファイルに対しては ".." です。 .NET Framework プロジェクトの場合、build context はソリューション フォルダーではなく、プロジェクト フォルダーです。

docker build -f Dockerfile ..

プロジェクトのウォームアップ

プロジェクトのウォームアップとは、後続の実行 (F5 キーまたは Ctrl+F5 キー) のパフォーマンスを向上させるために、プロジェクトの Docker プロファイルが選択されたとき (つまり、プロジェクトが読み込まれたとき、または Docker のサポートが追加されたとき) に実行される一連の手順を指します。 この動作は、[ツール]>[オプション]>[コンテナー ツール] で構成できます。 バックグラウンドでは、次のタスクが実行されます。

  • Docker Desktop がインストールされ、実行されていることを確認します。
  • Docker Desktop がプロジェクトと同じオペレーティング システムに設定されていることを確認します。
  • Dockerfile の最初のステージ (ほとんどの Dockerfile では base ステージ) でイメージをプルします。
  • Dockerfile をビルドし、コンテナーを開始します。

ウォームアップは高速モードでのみ発生するため、実行中のコンテナーには app フォルダーがボリューム マウントされています。 つまり、アプリに変更を加えてもコンテナーは無効になりません。 この動作により、デバッグのパフォーマンスが大幅に向上し、大きなイメージのプルなどの長時間実行されるタスクの待機時間が短縮されます。

ボリューム マッピング

デバッグをコンテナーで機能させるために、Visual Studio では、ボリューム マッピングを使用してホスト マシンからデバッガーと NuGet フォルダーをマップします。 ボリューム マッピングの詳細については、Docker のドキュメント (こちら) を参照してください。 コンテナーのボリューム マッピングを表示するには、Visual Studio の [コンテナー] ウィンドウを使用します。

コンテナーにマウントされるボリュームは次のとおりです。

ボリューム 説明
アプリ フォルダー Dockerfile が配置されているプロジェクト フォルダーが含まれています。
NuGet パッケージのフォルダー プロジェクトの obj{project}.csproj.nuget.g.props ファイルから読み取る NuGet パッケージとフォールバック フォルダーが含まれています。
リモート デバッガー プロジェクトの種類に応じて、コンテナーでデバッガーを実行するために必要なビットが含まれています。 「デバッグ」セクションを参照してください。
ソース フォルダー Docker コマンドに渡されるビルド コンテキストが含まれています。

コンテナーにマウントされるボリュームは次のとおりです。 コンテナーに表示される内容は、使用している Visual Studio 2022 のマイナー バージョンによって異なる場合があります。

体積 説明
アプリ フォルダー Dockerfile が配置されているプロジェクト フォルダーが含まれています。
HotReloadAgent ホット リロード エージェントのファイルが含まれます。
HotReloadProxy ホスト リロード エージェントがホスト上の Visual Studio と通信できるようにするためのサービスの実行に必要なファイルが含まれます。
NuGet パッケージのフォルダー プロジェクトの obj{project}.csproj.nuget.g.props ファイルから読み取る NuGet パッケージとフォールバック フォルダーが含まれています。
リモート デバッガー プロジェクトの種類に応じて、コンテナーでデバッガーを実行するために必要なビットが含まれています。 これについては、「デバッグ」のセクションで詳しく説明します。
ソース フォルダー Docker コマンドに渡されるビルド コンテキストが含まれています。
TokenService.Proxy VisualStudioCredential がホスト上の Visual Studio と通信できるようにするためのサービスの実行に必要なファイルが含まれます。

.NET 8 では、ユーザー シークレットと HTTPS 証明書が含まれる、アプリ ユーザー用の追加のマウント ポイントがルートに存在する場合があります。 Visual Studio 17.10 プレビューでは、ホット リロードとトークン サービスのボリュームが、別のコンポーネントである Distroless Helper と共に、単一のマウント ポイント /VSTools で結合されます。

Note

Visual Studio 17.10 プレビュー Docker Desktop を使用せずに Linux 用 Windows サブシステム (WSL) で Docker Engine を使用している場合は、ボリューム マウントの作成時に Visual Studio が WSL パスを使用するように環境変数 VSCT_WslDaemon=1 を設定します。 NuGet パッケージ Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.20.0-Preview 1 も必要です。

ASP.NET CoreWeb アプリの場合、SSL 証明書とユーザー シークレット用にさらに 2 つのフォルダーが存在する場合があります。詳細については、次のセクションを参照してください。

詳細なコンテナー ツール ログを有効にする

診断の目的で、特定のコンテナー ツール ログを有効にできます。 これらのログを有効にするには、特定の環境変数を設定します。 単一コンテナー プロジェクトの場合、環境変数は 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 認証を構成する」をご覧ください。

コンテナーのエントリ ポイント

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 Web アプリの場合、エントリ ポイントはわずかに異なり、ServiceMonitor がコマンドに追加されます。

コンテナー エントリ ポイントは、単一コンテナー プロジェクトではなく、Docker Compose プロジェクトでのみ変更できます。

SSL 対応 ASP.NET Core アプリ

Visual Studio のコンテナー ツールは、コンテナーがない場合に想定される方法で、開発証明書を使用した SSL 対応 ASP.NET Core アプリのデバッグをサポートしています。 それを実現するために、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"
      }
    }
  }
}

構成でコンテナー化されたビルドとコンテナー化されていないビルドの両方がサポートされている場合は、環境変数を使用する必要があります。これは、パスがコンテナー環境に固有であるためです。

コンテナー内の ASP.NET Core アプリで SSL を使用する方法の詳細については、「HTTPS 経由で Docker を使用して ASP.NET Core イメージをホストする」を参照してください。

ホストと HTTPS サービス間通信用のコンテナーで信頼されているマルチサービス アプリのカスタム証明書の作成を示すコード サンプルについては、「CertExample」を参照してください。