インドカレーファンクラブ

パソコン、カメラ

【.NET】.NETなアプリケーションをVisualStudioからdocker-compose upしようとすると暗黙的にentrypointがoverrideされるせいでwait-for-itが無視される問題

いつかこの辺のつくりが便利になっていることを願って(執筆時2021/02/23)

概要

単純にコマンドでdocker-compose build, docker-compose upするなら問題ないんだけど、
VisualStudioのDocker連携によって追加したdocker-composeプロジェクト(素直に作った場合docker-compose.dcprojになるかな)をスタートアッププロジェクトに指定し、起動した場合はentrypointもといdocker-compose.ymlそのものが暗黙的に上書きされることになる

GUIをもってWebAPをDocker連携を行うようにしていくと、Dokcerfile, docker-compose.ymlだけでなくdocker-compose.override.ymlも自動生成されるんだけど、それとはまた別

その暗黙的な上書きを、更に明示的に上書きする場合の手順のまとめというかサンプルというかを書いた記事

上書きで困る具体的な例(表題のやつ):
WebAPの起動の前にDBの疎通を待つためにwait-for-it.shのcallをWebAPのentrypointとして指定する
(VisualStudioのGUIからdocker-composeを起動する場合、)そのentrypointが上書きされて無視されてしまう
※ wait-for-it自体はDocker的に推奨される方法 https://docs.docker.jp/compose/startup-order.html

ローカルでGUI操作の時だけの問題というかVisualStudioのローカルでバッグの問題なんだから無視でいいじゃん。とも(後から)思ったけど、そこを考えずに必死に調べて結論まで出してしまった...

方法

you could add the following code only in docker-compose.vs.debug.yml

If you omit the docker-compose.vs.release.yml or docker-compose.vs.debug.yml then Visual Studio generates one based on default settings.

https://docs.microsoft.com/ja-jp/visualstudio/containers/docker-compose-properties?view=vs-2019#customize-the-app-startup-process

この通りdocker-compose.vs.debug.ymlを上書きすればいい
さもないとdefault settingが利用される

※ そのdefault settingを記述しているファイル自体は自動生成されるが、ソリューションに包含されない(なので分かりにくい)

If you want to take a peek at all the drudgery, take a look at the file: {root solution folder}\obj\Docker\docker-compose.vs.debug.g.yml

https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/docker-application-development-process/docker-app-development-workflow#option-b-running-a-multi-container-application

実装

wait-for-itを利用する例で説明
せっかくなのでgithubにあげた
VisualStudio For MacでやっているのでWindowsだとパス変えなきゃだめかも(いつか自分で確認する)

https://github.com/0mmadawn/VsDebugDockerContainerOverrideSample

まずはwait-for-itを準備する

https://github.com/0mmadawn/VsDebugDockerContainerOverrideSample/blob/main/web/Dockerfile#L8-L9

(本筋から逸れるけど、)CLIからdocker-compose upする場合は以下の通り普通にdocker-compose.ymlにentrypointを書けばOK

https://github.com/0mmadawn/VsDebugDockerContainerOverrideSample/blob/main/docker-compose.yml#L13-L14

本題のVisualStudioからGUI操作でdocker-composeプロジェクトを起動する場合のために、docker-compose.vs.debug.ymlファイルを明示的に用意する

でこんな感じ

version: '3.4'

services:
  web:
    # 省略

    # entrypointはそのままでOK
    entrypoint: tail -f /dev/null

    labels:
      # これを
      #com.microsoft.visualstudio.debuggee.program: "dotnet"
      #com.microsoft.visualstudio.debuggee.arguments: " --additionalProbingPath /root/.nuget/packages  \"/app/bin/Debug/net5.0/web.dll\""
      # こうする
      com.microsoft.visualstudio.debuggee.program: "/wait-for-it.sh"
      com.microsoft.visualstudio.debuggee.arguments: "db:3306 -t 60 -- dotnet --additionalProbingPath /root/.nuget/packages \"/app/bin/Debug/net5.0/web.dll\""
    # 省略

https://github.com/0mmadawn/VsDebugDockerContainerOverrideSample/blob/main/docker-compose.vs.debug.yml#L28-L29

entrypointはそのままにlabelsのよくわからんところを変更するのがポイント

偉大なる参考: https://github.com/microsoft/DockerTools/issues/9#issuecomment-613042120

で、動かすとこんな感じに確認できる

Starting: "docker" exec -i fcda4d199535 /bin/sh -c "ID=.; if [ -e /etc/os-release ]; then . /etc/os-release; fi; if [ $ID = alpine ] && [ -e /remote_debugger/linux-musl-x64/vsdbg ]; then VSDBGPATH=/remote_debugger/linux-musl-x64; else VSDBGPATH=/remote_debugger; fi; $VSDBGPATH/vsdbg --interpreter=vscode --interpreter=vscode"
-------------------------------------------------------------------
You may only use the Microsoft .NET Core Debugger (vsdbg) with
Visual Studio Code, Visual Studio or Visual Studio for Mac software
to help you develop and test your applications.
-------------------------------------------------------------------
wait-for-it.sh: waiting 60 seconds for db:3306        ★呼ばれてる!
wait-for-it.sh: db:3306 is available after 22 seconds ★
Loaded '/usr/share/dotnet/shared/Microsoft.NETCore.App/5.0.2/System.Private.CoreLib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
...

補足

docker-compose.vs.debug.ymlファイルで自分のローカルなファイル参照させてるし、 なんならこっちの方法のようにプログラム内で制御したほうがマシな気がしてきている https://stackoverflow.com/a/53238408