銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Visual Studio から AzureやWindows以外のdocker containerで走るASP.NET Core をリモートデバッグする

空いていたので予定を早めて Visual Studio Advent Calendar 12日目のエントリを書きます。

qiita.com

Windows上のdockerやAzure Container ServicesであればVisual Studio Tools for Dockerを使えばVisual StudioからASP.NET Coreのアプリにリモートデバッグできます。Microsoft謹製のサービスしか接続できないので、なにか闇の技術でも使われているかと思われるかもしれないですが、そんなことはなくてGitHubで公開されているMIEngineというデバッグエンジンが利用されています。

github.com

この当たりの話は、Visual StudioからSSHを使えば、Linux上の.NET Coreプロセスにリモートデバッグできるというネタで何度かセッションでデモをしてきました。

というわけで、Visual StudioをインストールしているWindowsマシンからdockerにリモートでコマンドを実行できれば、他のdocker containerであってもリモートデバッグができます。今回は、OpenShift Container Platform上で動くASP.NET Coreアプリにリモート接続してみます。

前提条件

OpenShift で試していますが、以下の条件を満たせば他のdocker container as a service なプラットフォームでも同じ方法が使えるはずです*1

  • docker exec コマンドなどでVS Codeを動かしているマシンからリモートでコンテナ上のコマンドを実行できる
  • docker上で動いているASP.NET Core のバイナリはデバッグビルドである

手順

前提条件を満たしたdockerが動ている前提からスタートします。OpenShiftの場合は、gitのコードリポジトリにあるソースコードからビルドしてdocker containerを作って動かすs2iという仕組みがあるので、それが使えます。今回テストしたアプリも下のexampleアプリをそのまま動かしただけの状態です。

GitHub - openshift-s2i/s2i-aspnet-example: Example projects for the ASP.NET builder image

Visual Studioを動かすマシンにソースコードをセットアップします。上のコードを使う場合はcloneしてappフォルダ以下をルートとして開けばOKです。

実行しているdocker container内にclrdbgをインストールします。インストール先などは適当に。あらかじめclrdbgをインストールしたdockerイメージを用意してもいいでしょう。OpenShiftの場合はoc exec [pod] -- [command]でコマンドを実行できます*2docker execの場合はコマンドの前の--が不要です。

> oc exec <POD_NAME> -- curl -sSL https://raw.githubusercontent.com/Microsoft/MIEngine/getclrdbg-release/scripts/GetClrDbg.sh -o GetClrDbg.sh
> oc exec <POD_NAME> -- bash ./GetClrDbg.sh latest ./clrdbg
Info: Using clrdbg version '15.0.25904-preview-3404276'
Info: Creating install directory
Info: Determinig Runtime ID
Info: Using Runtime ID 'rhel.7.2-x64'
Info: Generating project.json
Info: Generating NuGet.config
Info: Executing dotnet restore
Info: Executing dotnet publish
Successfully installed clrdbg at './clrdbg'

次にプロセスにアタッチするので、コンテナ上で動いているASP.NET Core のPIDを確認します。OpenShiftの場合はこんな結果になりますが、PIDは62になります。

> oc exec <POD_NAME> -- ps aux 
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
default       1  0.5  0.4 3048552 37016 ?       SLsl 22:08   0:05 dotnet run
default      62  1.0  1.9 12134016 153332 ?     SLl  22:08   0:09 /opt/rh/rh-dotnetcore10/root/usr/lib64/dotnetcore/dotnet exec --additionalprobingpath /opt/app-root/src/.nuget/packages /opt/app-root/src/bin/Debug/netcoreapp1.0/src.dll
default     381  0.0  0.0  13352  1868 ?        Ss+  22:16   0:00 /bin/sh
default     676  0.0  0.0  48996  1692 ?        Rs   22:23   0:00 ps aux

接続先のコンテナ名(POD名)とPIDがわかれば次のようなXMLファイルを作成します。これはVisual Studioのプロジェクト内でも外でもどちらに保存しても構いません。<POD_NAME>とを置き換えてください。docker execやkubectrlの場合もdockerやkubectlのフルパスと、--を除いたコマンド引数を指定すれば大丈夫なはずです。

<PipeLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014"
  PipePath="C:\Tools\oc.exe" PipeArguments="exec -i <POD_NAME> -- /opt/app-root/src/clrdbg/clrdbg --interpreter=mi"
  TargetArchitecture="x64" MIMode="clrdbg">
  <CustomLaunchSetupCommands>
    <Command>-target-attach <PID></Command>
  </CustomLaunchSetupCommands>
  <LaunchCompleteCommand>None</LaunchCompleteCommand>
</PipeLaunchOptions>

あとは、Visual StudioのCommand Windowを開いて、

> Debug.MIDebugLaunch /Executable:dotnet /OptionsFile:<保存したxmlファイルのパス>

を実行します。あとは自動でデバッグが始まってプロセスにアタッチできるはずです。もちろん、ブレークポイントをしかけるとブレークします。

f:id:tanaka733:20161212152723p:plain

なかなか面倒な手順ですが、Visual Studio Tools for Docker はOpen Sourceになるらしいので、公開されたらそれをいじればVS拡張として作ることも簡単そうです。

blogs.msdn.microsoft.com

ちなみにVisual Studio Codeからも同じことができますが、それは今週末のAdvent Calendarに書きます。

qiita.com

*1:kubernetesを直に動かしている場合もkubectl execで同じことができるはずです

*2:podはOpenShiftが内包しているkubernetesがcontainerを管理する単位