チュートリアル: .NET アプリをコンテナー化する
このチュートリアルでは、Docker を使用して .NET アプリケーションをコンテナー化する方法について説明します。 コンテナーには、不変のインフラストラクチャであること、移植可能なアーキテクチャを提供すること、スケーラビリティを実現するなど、多くの機能と利点があります。 イメージを使用して、ローカル開発環境、プライベート クラウド、またはパブリック クラウド用のコンテナーを作成できます。
このチュートリアルでは、次の操作を行います。
- 単純な .NET アプリを作成して発行する
- .NET 用の Dockerfile を作成して構成する
- Docker イメージをビルドする
- Docker コンテナーを作成して実行する
.NET アプリケーションの Docker コンテナーのビルドタスクとデプロイ タスクについて説明します。
ヒント
Docker または Podman を必要とせずに .NET アプリをコンテナーとして発行することに関心がある場合は、「dotnet publishを使用して .NET アプリをコンテナー化する
手記
このチュートリアル は ASP.NET Core アプリを対象としているわけではありません。 ASP.NET Core を使用している場合は、ASP.NET Core アプリケーションをコンテナー化する方法 チュートリアル
前提 条件
次の前提条件をインストールします。
- .NET 8+ SDK。
.NET がインストールされている場合は、dotnet --info
コマンドを使用して、使用している SDK を特定します。 - Docker Community Edition。
- Dockerfile および .NET サンプル アプリの一時作業フォルダー。 このチュートリアルでは、docker 作業
名前を作業フォルダーとして使用します。
.NET アプリを作成する
Docker コンテナーが実行される .NET アプリが必要です。 ターミナルを開き、作業フォルダーをまだ作成していない場合は作成し、入力します。 作業フォルダーで、次のコマンドを実行して、Appという名前
dotnet new console -o App -n DotNet.Docker
フォルダー ツリーは、次のディレクトリ構造のようになります。
📁 docker-working
└──📂 App
├──DotNet.Docker.csproj
├──Program.cs
└──📂 obj
├── DotNet.Docker.csproj.nuget.dgspec.json
├── DotNet.Docker.csproj.nuget.g.props
├── DotNet.Docker.csproj.nuget.g.targets
├── project.assets.json
└── project.nuget.cache
dotnet run
コマンドを使用してアプリを起動します。 アプリケーションが実行され、コマンドの下に Hello World!
出力されます。
cd App
dotnet run
Hello World!
既定のテンプレートは、ターミナルに出力してすぐに終了するアプリを作成します。 このチュートリアルでは、無期限にループするアプリを使用します。 テキスト エディターで Program.cs ファイルを開きます。
ヒント
Visual Studio Code を使用している場合は、前のターミナル セッションから次のコマンドを入力します。
code .
このコマンドを実行すると、Visual Studio Code でプロジェクトを含む App フォルダーが開きます。
Program.cs は次の C# コードのようになります。
Console.WriteLine("Hello World!");
ファイルを、1 秒ごとに数値をカウントする次のコードに置き換えます。
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
var counter = 0;
var max = args.Length is not 0 ? Convert.ToInt32(args[0]) : -1;
while (max is -1 || counter < max)
{
Console.WriteLine($"Counter: {++counter}");
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
}
ファイルを保存し、dotnet run
でプログラムをもう一度テストします。 このアプリは無期限に実行されます。 ctrl + C
dotnet run
Counter: 1
Counter: 2
Counter: 3
Counter: 4
^C
コマンド ライン上の数値をアプリに渡すと、カウントはその量に制限され、終了します。 dotnet run -- 5
を使用して 5 個までカウントしてみてください。
重要
--
後のパラメーターは、dotnet run
コマンドには渡されず、代わりにアプリケーションに渡されます。
.NET アプリを発行する
アプリがイメージの作成に適するようにするには、コンパイルする必要があります。 dotnet publish
コマンドは、アプリをビルドして発行する際に最も適しています。 詳細なリファレンスについては、
dotnet publish -c Release
アドバイス
Docker を必要とせずに .NET アプリをコンテナーとして発行することに関心がある場合は、「dotnet publishを使用して .NET アプリをコンテナー化する
dotnet publish
コマンドは、アプリを publish フォルダーにコンパイルします。 作業フォルダーダから publish フォルダーへのパスは ./App/bin/Release/<TFM>/publish/ になります。
App フォルダーから、発行フォルダーのディレクトリ一覧を取得して、DotNet.Docker.dll ファイルが作成されたことを確認します。
dir .\bin\Release\net9.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net9.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 1/6/2025 10:11 AM 431 DotNet.Docker.deps.json
-a---- 1/6/2025 10:11 AM 6144 DotNet.Docker.dll
-a---- 1/6/2025 10:11 AM 145408 DotNet.Docker.exe
-a---- 1/6/2025 10:11 AM 11716 DotNet.Docker.pdb
-a---- 1/6/2025 10:11 AM 340 DotNet.Docker.runtimeconfig.json
dir .\bin\Release\net8.0\publish\
Directory: C:\Users\default\docker-working\App\bin\Release\net8.0\publish
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/22/2023 9:17 AM 431 DotNet.Docker.deps.json
-a--- 9/22/2023 9:17 AM 6144 DotNet.Docker.dll
-a--- 9/22/2023 9:17 AM 157696 DotNet.Docker.exe
-a--- 9/22/2023 9:17 AM 11688 DotNet.Docker.pdb
-a--- 9/22/2023 9:17 AM 353 DotNet.Docker.runtimeconfig.json
Dockerfile を作成する
Dockerfile ファイルは、docker build
コマンドによってコンテナー イメージを作成するために使用されます。 このファイルは、拡張子のない Dockerfile
.csproj を含むディレクトリ Dockerfile という名前のファイルを作成し、テキスト エディターで開きます。 このチュートリアルでは、ASP.NET Core ランタイム イメージ (.NET ランタイム イメージを含む) を使用し、.NET コンソール アプリケーションに対応します。
FROM mcr.microsoft.com/dotnet/sdk:9.0@sha256:3fcf6f1e809c0553f9feb222369f58749af314af6f063f389cbd2f913b4ad556 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:9.0@sha256:b4bea3a52a0a77317fa93c5bbdb076623f81e3e2f201078d89914da71318b5d8
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
手記
ASP.NET Core ランタイム イメージはここでは意図的に使用されますが、代わりに mcr.microsoft.com/dotnet/runtime:9.0
イメージを使用することもできます。
FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:6c4df091e4e531bb93bdbfe7e7f0998e7ced344f54426b7e874116a3dc3233ff
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
手記
ASP.NET Core ランタイム イメージはここでは意図的に使用されますが、代わりに mcr.microsoft.com/dotnet/runtime:8.0
イメージを使用することもできます。
重要
Dockerfile でイメージタグの後にセキュアハッシュアルゴリズム (SHA) を含めることはベストプラクティスです。 これにより、イメージが改ざんされず、イメージが予期したイメージと同じであることが保証されます。 SHA はイメージの一意識別子です。 詳細については、「Docker ドキュメント: ダイジェストでイメージをプルする」を参照してください。
ヒント
この Dockerfile では、ビルドを重ねて必要な成果物のみを残すことで、イメージの最終的なサイズを最適化するマルチステージ ビルドを使用します。 詳細については、「Docker Docs: マルチステージ ビルド」を参照してください。
FROM
キーワードには、完全修飾 Docker コンテナー イメージ名が必要です。 Microsoft Container Registry (MCR、mcr.microsoft.com) は、パブリックにアクセス可能なコンテナーをホストする Docker Hub のシンジケートです。 dotnet
セグメントはコンテナー リポジトリですが、sdk
または aspnet
セグメントはコンテナー イメージ名です。 イメージには、バージョン管理に使用される 9.0
がタグ付けされています。 したがって、mcr.microsoft.com/dotnet/aspnet:9.0
は .NET 9.0 ランタイムです。 必ず、SDK の対象となるランタイムと一致するランタイム バージョンをプルしてください。 たとえば、前のセクションで作成したアプリは .NET 9.0 SDK を使用し、Dockerfile で参照される基本イメージには、9.0でタグ付けされています。
重要
Windows ベースのコンテナー イメージを使用する場合は、mcr.microsoft.com/dotnet/aspnet:9.0
ではなく、mcr.microsoft.com/dotnet/aspnet:9.0-nanoserver-1809
など、単に 9.0
を超えてイメージ タグを指定する必要があります。 Nano Server と Windows Server Core のどちらを使用しているか、およびその OS のバージョンに基づいてイメージ名を選択します。 サポートされているすべてのタグの完全なリストは、.NET の Docker Hub ページで確認できます。
Dockerfile ファイルを保存します。 作業フォルダーのディレクトリ構造は次のようになります。 記事の領域を節約するために、より深いレベルのファイルとフォルダーの一部は省略されています。
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └───📂 Release
│ └───📂 net9.0
│ ├───📂 publish
│ │ ├─── DotNet.Docker.deps.json
│ │ ├─── DotNet.Docker.dll
│ │ ├─── DotNet.Docker.exe
│ │ ├─── DotNet.Docker.pdb
│ │ └─── DotNet.Docker.runtimeconfig.json
│ ├─── DotNet.Docker.deps.json
│ ├─── DotNet.Docker.dll
│ ├─── DotNet.Docker.exe
│ ├─── DotNet.Docker.pdb
│ └─── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
FROM
キーワードには、完全修飾 Docker コンテナー イメージ名が必要です。 Microsoft Container Registry (MCR、mcr.microsoft.com) は、パブリックにアクセス可能なコンテナーをホストする Docker Hub のシンジケートです。 dotnet
セグメントはコンテナー リポジトリですが、sdk
または aspnet
セグメントはコンテナー イメージ名です。 イメージには、バージョン管理に使用される 8.0
がタグ付けされています。 したがって、mcr.microsoft.com/dotnet/aspnet:8.0
は .NET 8.0 ランタイムです。 必ず、SDK の対象となるランタイムと一致するランタイム バージョンをプルしてください。 たとえば、前のセクションで作成したアプリは .NET 8.0 SDK を使用し、Dockerfile で参照される基本イメージには、8.0でタグ付けされています。
重要
Windows ベースのコンテナー イメージを使用する場合は、mcr.microsoft.com/dotnet/aspnet:8.0
ではなく、mcr.microsoft.com/dotnet/aspnet:8.0-nanoserver-1809
など、単に 8.0
を超えてイメージ タグを指定する必要があります。 Nano Server と Windows Server Core のどちらを使用しているか、およびその OS のバージョンに基づいてイメージ名を選択します。 .NET の Docker Hub ページでサポートされているすべてのタグの完全なリストを見つけることができます。
Dockerfile ファイルを保存します。 作業フォルダーのディレクトリ構造は次のようになります。 記事の領域を節約するために、より深いレベルのファイルとフォルダーの一部は省略されています。
📁 docker-working
└──📂 App
├── Dockerfile
├── DotNet.Docker.csproj
├── Program.cs
├──📂 bin
│ └──📂 Release
│ └──📂 net8.0
│ └──📂 publish
│ ├── DotNet.Docker.deps.json
│ ├── DotNet.Docker.exe
│ ├── DotNet.Docker.dll
│ ├── DotNet.Docker.pdb
│ └── DotNet.Docker.runtimeconfig.json
└──📁 obj
└──...
ENTRYPOINT
命令は、DotNet.Docker.dll
のホストとして dotnet
を設定します。 ただし、代わりに、アプリの実行可能ファイル自体として ENTRYPOINT
を定義し、アプリ ホストとして OS に依存することもできます。
ENTRYPOINT ["./DotNet.Docker"]
これにより、アプリは dotnet
せずに直接実行され、代わりにアプリ ホストと基になる OS に依存します。 クロスプラットフォーム バイナリのデプロイの詳細については、「クロスプラットフォーム バイナリを生成する」を参照してください。
コンテナーをビルドするには、ターミナルから次のコマンドを実行します。
docker build -t counter-image -f Dockerfile .
Docker は、Dockerfile内の各行を処理します。 docker build
コマンドの .
は、イメージのビルド コンテキストを設定します。 -f
スイッチは、Dockerfileへのパスです。 このコマンドでは、イメージがビルドされて、そのイメージを指す counter-image という名前のローカル リポジトリが作成されます。 このコマンドが完了したら、docker images
を実行して、インストールされているイメージの一覧を表示します。
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 1c1f1433e51d 32 seconds ago 223MB
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
counter-image latest 2f15637dc1f6 10 minutes ago 217MB
counter-image
リポジトリはイメージの名前です。 さらに、イメージ タグ、イメージ識別子、サイズ、および作成時はすべて出力の一部です。 Dockerfile の最後の手順は、イメージからコンテナーを作成してアプリを実行し、発行されたアプリをコンテナーにコピーして、エントリ ポイントを定義することです。
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
FROM
コマンドは、使用する基本イメージとタグを指定します。 WORKDIR
コマンドは、コンテナー内の 現在のディレクトリ を Appに変更します。
COPY
コマンドは、指定したソース ディレクトリをコピー先フォルダーにコピーするように Docker に指示します。 この例では、build
レイヤーの publish コンテンツが App/out という名前のフォルダーに出力されるため、これがコピー元になります。 App/out ディレクトリ内のすべての発行済みコンテンツは、現在の作業ディレクトリ (App) にコピーされます。
次のコマンド ENTRYPOINT
は、実行可能ファイルとして実行するようにコンテナーを構成するように Docker に指示します。 コンテナーが起動すると、ENTRYPOINT
コマンドが実行されます。 このコマンドが終了すると、コンテナーは自動的に停止します。
ヒント
.NET 8 より前では、読み取り専用として実行するように構成されたコンテナーは、Failed to create CoreCLR, HRESULT: 0x8007000E
で失敗する可能性があります。 この問題に対処するには、DOTNET_EnableDiagnostics
環境変数を 0
として指定します (ENTRYPOINT
ステップの直前)。
ENV DOTNET_EnableDiagnostics=0
さまざまな .NET 環境変数の詳細については、「.NET 環境変数
手記
.NET 6 では、.NET ランタイム動作を構成する環境変数の COMPlus_
ではなく、プレフィックス DOTNET_
が標準化されています。 ただし、COMPlus_
プレフィックスは引き続き機能します。 以前のバージョンの .NET ランタイムを使用している場合でも、環境変数には COMPlus_
プレフィックスを使用する必要があります。
コンテナーを作成する
アプリを含むイメージが作成されたので、コンテナーを作成できます。 コンテナーは 2 つの方法で作成できます。 まず、停止している新しいコンテナーを作成します。
docker create --name core-counter counter-image
この docker create
コマンドは、カウンター イメージの イメージに基づいてコンテナーを作成します。 docker create
コマンドの出力には、コンテナーの CONTAINER ID が表示されます (識別子は異なります)。
d0be06126f7db6dd1cee369d911262a353c9b7fb4829a0c11b4b2eb7b2d429cf
すべての コンテナー
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d0be06126f7d counter-image "dotnet DotNet.Docke…" 12 seconds ago Created core-counter
コンテナーを管理する
コンテナーは、特定の名前 core-counter
で作成されました。 この名前は、コンテナーの管理に使用されます。 次の例では、docker start
コマンドを使用してコンテナーを起動し、docker ps
コマンドを使用して、実行中のコンテナーのみを表示します。
docker start core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf01364df453 counter-image "dotnet DotNet.Docke…" 53 seconds ago Up 10 seconds core-counter
同様に、docker stop
コマンドはコンテナーを停止します。 次の例では、docker stop
コマンドを使用してコンテナーを停止し、docker ps
コマンドを使用してコンテナーが実行されていないことを示します。
docker stop core-counter
core-counter
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
コンテナーに接続する
コンテナーが実行されたら、コンテナーに接続して出力を確認できます。 docker start
コマンドと docker attach
コマンドを使用してコンテナを開始し、出力ストリームを確認します。 この例では、Ctrl + C キーストロークを使用して、実行中のコンテナーからデタッチします。 このキー操作では、特に指定しない限り、コンテナー内のプロセスが終了し、コンテナーが停止されます。
コンテナーからデタッチした後、再アタッチして、まだ実行中でカウントされていることを確認します。
docker start core-counter
core-counter
docker attach --sig-proxy=false core-counter
Counter: 7
Counter: 8
Counter: 9
^C
docker attach --sig-proxy=false core-counter
Counter: 17
Counter: 18
Counter: 19
^C
コンテナーを削除する
この記事では、何もしないコンテナーをぶら下げないようにします。 前に作成したコンテナーを削除します。 コンテナーが実行されている場合は、停止します。
docker stop core-counter
次の例では、すべてのコンテナーを一覧表示します。 その後、docker rm
コマンドを使用してコンテナーを削除し、2 回目に実行中のコンテナーを確認します。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f6424a7ddce counter-image "dotnet DotNet.Dock…" 7 minutes ago Exited (143) 20 seconds ago core-counter
docker rm core-counter
core-counter
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
単一実行
Docker には、コンテナーを 1 つのコマンドとして作成して実行するための docker run
コマンドが用意されています。 このコマンドを使用すると、docker create
を実行してから docker start
する必要がなくなります。 このコマンドは、コンテナーが停止したときにコンテナーを自動的に削除するように設定することもできます。 たとえば、docker run -it --rm
を使用して 2 つのことを行います。最初に、現在のターミナルを自動的に使用してコンテナーに接続し、コンテナーが完了したら削除します。
docker run -it --rm counter-image
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
^C
コンテナーは、.NET アプリの実行にもパラメーターを渡します。 .NET アプリにカウントを 3 つだけにするように指示するには、3 を渡します。
docker run -it --rm counter-image 3
Counter: 1
Counter: 2
Counter: 3
docker run -it
では、Ctrl + C コマンドによってコンテナーで実行されているプロセスが停止され、コンテナーが停止されます。 --rm
パラメーターが指定されたため、プロセスが停止するとコンテナーが自動的に削除されます。 存在しないことを確認します。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ENTRYPOINT を変更する
docker run
コマンドを使用すると、Dockerfile から ENTRYPOINT
コマンドを変更し、そのコンテナーに対してのみ何かを実行することもできます。 たとえば、次のコマンドを使用して、bash
または cmd.exe
を実行します。 必要に応じてコマンドを編集します。
この例では、ENTRYPOINT
は cmd.exe
に変更されています。 Ctrl + C を押してプロセスを終了し、コンテナーを停止します。
docker run -it --rm --entrypoint "cmd.exe" counter-image
Microsoft Windows [Version 10.0.17763.379]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\>dir
Volume in drive C has no label.
Volume Serial Number is 3005-1E84
Directory of C:\
04/09/2019 08:46 AM <DIR> app
03/07/2019 10:25 AM 5,510 License.txt
04/02/2019 01:35 PM <DIR> Program Files
04/09/2019 01:06 PM <DIR> Users
04/02/2019 01:35 PM <DIR> Windows
1 File(s) 5,510 bytes
4 Dir(s) 21,246,517,248 bytes free
C:\>^C
手記
この例は、Windows コンテナーでのみ機能します。 Linux コンテナーには cmd.exe
がありません。
基本的なコマンド
Docker には、コンテナーとイメージを作成、管理、操作するさまざまなコマンドがあります。 コンテナーの管理には、次の Docker コマンドが不可欠です。
リソースのクリーンアップ
このチュートリアルでは、コンテナーとイメージを作成しました。 必要な場合は、これらのリソースを削除します。 次のコマンドを使います
すべてのコンテナーを一覧表示する
docker ps -a
実行しているコンテナーを名前で選んで停止します。
docker stop core-counter
コンテナーを削除する
docker rm core-counter
次に、コンピューターに不要になったイメージを削除します。 Dockerfile によって作成されたイメージを削除し、Dockerfile の基になっていた .NET イメージを削除します。 IMAGE ID または REPOSITORY:TAG 書式設定された文字列を使用できます。
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:9.0
docker rmi counter-image:latest
docker rmi mcr.microsoft.com/dotnet/aspnet:8.0
docker images
コマンドを使用して、インストールされているイメージの一覧を表示します。
ヒント
イメージ ファイルは大きくなる場合があります。 通常は、アプリのテストと開発中に作成した一時コンテナーを削除します。 通常、そのランタイムに基づいて他のイメージをビルドする予定の場合は、ランタイムがインストールされた状態で基本イメージを保持します。
次の手順
- dotnet publish を使用して .NET アプリをコンテナー化する
- .NET コンテナー イメージ
- ASP.NET Core アプリケーション をコンテナー化する
- コンテナーをサポートする Azure サービス
- Dockerfile コマンド
- Visual Studio のコンテナー ツール
.NET