Share via


診断ポート

この記事の対象: ✔️ .NET Core 3.1 以降のバージョン

.NET ランタイムでは、他のプロセスが IPC チャネルを介して診断コマンドを送信し、応答を受信できるようにするためにサービス エンドポイントを公開します。 このエンドポイントは、"診断ポート" と呼ばれます。 診断ポートには、以下のためにコマンドを送信できます。

  • メモリ ダンプをキャプチャする。
  • EventPipe トレースを開始する。
  • アプリの起動に使用するコマンド ラインを要求する。

診断ポートでは、プラットフォームに応じてさまざまなトランスポートがサポートされます。 現在、CoreCLR ランタイムおよび Mono ランタイム実装の両方で、Windows用の名前付きパイプと、Linux および macOS 用の Unix ドメイン ソケットが使用されています。 Android、iOS、および tvOS に対する Mono ランタイムの実装では、TCP/IP が使用されます。 このチャネルでは、カスタム バイナリ プロトコルが使用されます。 開発者のほとんどは、基になるチャネルやプロトコルと直接対話することはなく、自動的に通信してくれる GUI または CLI ツールを使用します。 たとえば、dotnet-dump および dotnet-trace ツールを使用すると、ダンプをキャプチャしてトレースを開始するためのプロトコル コマンドの送信が抽象化されます。 カスタム ツールを作成する開発者向けの Microsoft.Diagnostics.NETCore.Client NuGet パッケージは、基になるトランスポートとプロトコルの .NET API 抽象化を実現します。

セキュリティに関する考慮事項

診断ポートでは、実行中のアプリケーションに関する機密情報を公開します。 信頼されていないユーザーがこのチャネルにアクセスすると、メモリ内にあるシークレットを含む詳細なプログラムの状態を観察し、プログラムの実行を任意に変更できます。 CoreCLR ランタイム上で、既定の診断ポートは、アプリを起動したのと同じユーザー アカウントから、またはスーパーユーザーアクセス許可を持つアカウントからのみアクセスできるように構成されています。 セキュリティ モデルで、同じユーザー アカウント資格情報を持つ他のプロセスが信頼されていない場合は、環境変数 DOTNET_EnableDiagnostics=0 を設定することで、すべての診断ポートを無効にすることができます。 この設定により、.NET デバッグや dotnet-* 診断ツールなどの外部ツールを使用できなくなります。

Note

.NET 6 では、.NET の実行時の動作を構成する環境変数のプレフィックスが、COMPlus_ ではなく DOTNET_ に標準化されています。 ただし、プレフィックス COMPlus_ は引き続き機能します。 以前のバージョンの .NET ランタイムを使用している場合は、環境変数に COMPlus_ プレフィックスをまだ使用する必要があります。

既定の診断ポート

Windows、Linux、および macOS 上では、ランタイムには、既定で、既知のエンドポイントに 1 つの診断ポートが開かれています。 これは、dotnet-* 診断ツールが代替ポートを使用するように明示的に構成されていない場合に、自動的に接続されるポートです。 エンドポイントは、次のとおりです。

  • Windows - 名前付きパイプ \\.\pipe\dotnet-diagnostic-{pid}
  • Linux および macOS - Unix ドメイン ソケット {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

{pid} は 10 進数で記述されたプロセス IDです。{temp} は、環境変数 TMPDIR、または TMPDIR が未定義/空の場合は値 /tmp となります。{disambiguation_key} は 10 進数で記述されたプロセス開始時刻です。 macOS および NetBSD では、プロセスの開始時間は UNIX エポック時間からの秒数です。 その他のすべてのプラットフォームでは、起動時からの時間となります。

起動時のランタイムを中断する

既定では、診断ツールが診断ポートに接続されているかどうかに関係なく、ランタイムが開始されるとすぐに、それによってマネージド コードが実行されます。 診断ツールが接続されるまで、ランタイムにマネージド コードの実行を待機させて、初期プログラムの動作を観察すると便利な場合があります。 環境変数 DOTNET_DefaultDiagnosticPortSuspend=1 を設定すると、ツールが既定のポートに接続するまでランタイムは待機します。 数秒経過してツールがアタッチされない場合、ツールのアタッチをまだ待機していることを説明する警告メッセージがランタイムからコンソールに出力されます。

追加の診断ポートを構成する

Note

これは、.NET 5 以降を実行しているアプリに対してのみ機能します。

Mono および CoreCLR ランタイムの両方で、connect ロールでカスタム構成済みの診断ポートを使用できます。 Mono では、Android または iOS 上で dotnet-dsrouter と共に使用する場合、listen ロール内のカスタム TCP/IP ポートもサポートされます。 これらのカスタム ポートは、引き続き使用可能な既定のポートに追加されます。 カスタム ポートが役立つ一般的な理由はいくつかあります。

  • Android、iOS、tvOS 上には既定のポートがないため、診断ツールを使用するにはポートを構成する必要があります。
  • コンテナーまたはファイアウォールを備えた環境では、既定のポートと同様に、プロセス ID に基づいて変化することのない予測可能なエンドポイント アドレスを設定できます。 その後、カスタム ポートを許可リストに明示的に追加するか、セキュリティ境界を越えてプロキシできます。
  • 監視ツールの場合は、エンドポイント上でツールにリッスンさせると便利であり、ランタイムはそれに対してアクティブに接続を試みます。 これにより、新しいアプリの起動を継続的にポーリングするための監視ツールが不要になります。 既定の診断ポートにアクセスできない環境では、監視対象アプリごとにカスタム エンドポイントを使用してモニターを構成する必要も回避できます。

診断ツールと .NET ランタイム間の各通信チャネルでは、一方がリスナーになって、もう一方が接続するのを待機する必要があります。 ランタイムは、任意のポートに対して、connect ロールで動作するように構成できます。 (Mono ランタイムは任意のポートに対して、listen ロール内で動作するように構成することもできます)。ポートは、診断ツールが再開コマンドを発行するのを待って、起動時に一時停止するように個別に構成することもできます。 接続するように構成されたポートでは、リモート エンドポイントがリッスンしていない場合、または接続が失われた場合に、接続試行が無期限に繰り返されます。 しかし、その接続の確立を待機している間、アプリでマネージド コードが自動的に一時停止されることはありません。 アプリで接続が確立されるまで待機する場合は、起動時に一時停止オプションを使用します。

カスタム ポートは、DOTNET_DiagnosticPorts 環境変数を使用して構成されます。 この変数は、セミコロンで区切られた、ポートの記述のリストに設定する必要があります。 各ポートの記述は、エンドポイント アドレスと、ランタイムの connect または listen のロールを制御するオプションの修飾子と、そのランタイムを起動時に一時停止する必要があるかどうかで構成されます。 Windows 上で、エンドポイント アドレスは、\\.\pipe\ プレフィックスのない名前付きパイプの名前です。 Linux および macOS 上で、それは Unix ドメイン ソケットへの完全なパスです。 Android、iOS、および tvOS 上では、アドレスは IP とポートです。 次に例を示します。

  1. DOTNET_DiagnosticPorts=my_diag_port1 - (Windows) ランタイムは名前付きパイプ \\.\pipe\my_diag_port1 に接続します。
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket - (Linux と macOS) ランタイムは Unix ドメイン ソケット /foo/tool1.socket/foo/tool2.socket に接続されます。
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 - (Android、iOS、および tvOS) ランタイムは、ポート 9000 上の IP 127.0.0.1 に接続します。
  4. DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend - (Linux および macOS) この例には、nosuspend 修飾子があります。 ランタイムでは、外部ツールによって作成される Unix ドメイン ソケット /foo/tool1.socket への接続が試みられます。 診断ポートが追加されると、通常、ランタイムは起動時に一時停止して再開コマンドを待機します。しかし、nosuspend によりランタイムが待機することはありません。

ポートの完全な構文は address[,(listen|connect)][,(suspend|nosuspend)] となります。 connect または listen のどちらも指定されていない場合は、connect が既定値です (そして listen は、Android または iOS 上の Mono ランタイムでのみサポートされます)。 suspend は、suspendnosuspend のどちらも指定されていない場合、既定値となります。

dotnet 診断ツールでの使用状況

dotnet-dumpdotnet-countersdotnet-trace などのすべてのツールでは、診断ポート経由で .NET アプリと通信する collect または monitor 動詞がサポートされています。

  • これらのツールで --processId 引数が使用されている場合、ツールでは既定の診断ポート アドレスを自動的に計算し、それに接続します。
  • 引数 --diagnostic-port を指定すると、ツールは指定されたアドレスでリッスンするため、環境変数 DOTNET_DiagnosticPorts を使用して接続するアプリを構成する必要があります。 dotnet カウンターの完全な例については、「診断ポートの使用」を参照してください。

ds-router を使用して診断ポートをプロキシする

dotnet-* 診断ツールはすべて、ローカルの名前付きパイプまたは Unix ドメイン ソケットである診断ポートに接続することを想定しています。 Mono は、多くの場合、分離されたハードウェア、または TCP 経由でプロキシを必要とするエミュレーターで実行することで、アクセス可能になります。 dotnet-dsrouter ツールでは、ローカルの名前付きパイプまたは Unix ドメイン ソケットを TCP にプロキシすることで、それらの環境でツールを使用できるようにします。 詳細については、「dotnet-dsrouter」を参照してください。