利用VS code 远程调试 docker 中的 dotnet 应用
前言
最近.Net 5 正式版发布,我也来蹭一点热度。
如题所示,我这次要讲的是debug docker中的dotnet应用。其实之前我已经写过类似主题的随笔,有兴趣回顾的朋友可以看看: VS code docker 调试 asp.net core
首先之前的随笔说得比较片面,由于当时也是刚刚接触docker和利用vscode写代码,并且当时遗留下来的几个问题也在本文中有了解决办法。
其次是随着docker的普及,vscode 原生支持远程调试。这些特点都降低调试docker中的应用的难度,而且这种技术,不仅仅限于dotnet,是可以覆盖到nodejs,python等等别的技术栈的。
在这篇随笔中就不在陈述为什么我们需要调试docker中的应用了,简单来说,是有这个需要。
是怎么实现的
这里贴一张vs code实现远程调试的原理图。
可以看出来,完整的代码,workspace 扩展组件,sdk,都是在远程的OS的,在我们的场景下,就是docker的容器下。
而我们本地的操作系统下,仅仅需要一些vs code和简单的组件。

本地操作系统必要应用/工具
1. VS code, 版本尽量新,我用的是1.51.0版本,vs code从什么版本开始支持remote server确实不知道了。
2. VS code extension :Remote Development. 他是一个pack,会同时安装上container, WSL, SSH的远程调试扩展。 是下图这个样子的

3. Docker for Desktop. 由于下文中会用到本地代码映射到container,所以需要用到完整的docker,而不仅仅是一个CLI。
4. hmm....应该就这些了,本机甚至不需要安装dotnet sdk和vscode 的c# 扩展。
5. 由于本地没有了sdk,我们还需要一份已经创建好的代码,由于时间的关系,我已经准备好了:
https://github.com/woailibain/remote-debug-sample
Getting Start
构建docker image
1. 到链接上checkout代码,打开vs code,然后打开git目录下的src。
在vs code上看到的是这个样子的,里面有一个sln文件,一个csproj。
2. 打开vs code下面的terminal窗口,或者可以打开系统下的CMD/terminal,然后cd到src目录下。
执行下面的命令
docker-compose build |
如果第一次操作这里会需要挺长的时间,是因为要到docker hub上pull sdk image。
等构建成功之后,会出现这种下图的这种提示

3. 我们使用docker命令再次校验是否已经生成了我们想要的image
docker images | grep remote-debug-sample |

Container 跑起来
1. 使用下面的命令,让container跑起来。我们可以在terminal/CMD上看到如下图类似的输出
1
|
docker-compose up |

2. 通过浏览器打开地址(http://localhost:5155/),就可以看到有一些内容了

调试
Attach to Container
1. 从vscode的侧边栏点开Remote Explorer
然后这里能看到你的docker中有什么Container。 如果是第一次使用,在Other Containers下,如果已经曾经使用了,就会在Container下

2. 右键需要用到的Container,然后点击attach to container

3. 稍等几秒,就会自动打开一个新的vscode窗口。 (如果你在开始之前并没有安装前面提到的Remote Development 扩展组件,则这里需要等待几分钟去完成安装,然后才会打开新的vscode窗口)
等vs code窗口打开后,窗口的右下角会出现Starting Dev Container的提示,我们点击它,就会出现TermIcal的窗口

点击上图的右下角的提示,就会出现Terminal 窗口,并且在左下角显示已经链接到kiwiho/remote-debug-sample这个container了

4.点击vs code旁边的Explorer,我们就能看到container上的代码已经能打开了,这里也特殊表明了这个是Container中的文件

5. 我们再随便打开其中一个C# 文件,就会自动安装C# 调试不要的必要扩展了。其实这里可以通过自定义文件完成扩展的自动安装,不过这里不展开说.
如果没有自动安装,请自行安装
6. 等C#扩展安装好之后,在debug 的地方,按照平常本地使用vs code的方式,创建一个调试配置文件。
在调试窗内点击create a launch.json file.

然后会有弹窗,我们选择dotnet Core

然后配置文件就生成了,我们主要用里面的.NET Core Attach。 其余不需要的可以自行删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version" : "0.2.0" , "configurations" : [ { "name" : ".NET Core Launch (web)" , "type" : "coreclr" , "request" : "launch" , "preLaunchTask" : "build" , "program" : "${workspaceFolder}/bin/Debug/net5.0/remote-debug-sample.dll" , "args" : [], "cwd" : "${workspaceFolder}" , "stopAtEntry" : false , "serverReadyAction" : { "action" : "openExternally" , "pattern" : "\\bNow listening on:\\s+(https?://\\S+)" }, "env" : { "ASPNETCORE_ENVIRONMENT" : "Development" }, "sourceFileMap" : { "/Views" : "${workspaceFolder}/Views" } }, { "name" : ".NET Core Attach" , "type" : "coreclr" , "request" : "attach" , "processId" : "${command:pickProcess}" } ] } |
开始调试
1. 启动 .NET Core Attach 调试配置。 我们在弹窗下选第一个,这里需要注意,我们要选自己运行的process。如果你用的是dotnet run,那就需要选择对应的process

在HomeController的Index方法最后一行打上断点,打开http://localhost:5155/Home
稍等一会儿,就能看到已经进去断点了。

我们需要的远程调试已经实现了
热部署和调试
其实在开发过程中,我们需要的很可能并不仅仅是调试,可能还需要修改代码。
那如果没改一次代码,都必须走完上面的全部步骤,那不是很坑吗。
所以我们需要引入dotnet watch 命令。
重点:但是要使用这种功能,container和代码必须要同一个台机! 前面的步骤都是能真正的远程调试,container可以运行在别的机器上。以下步骤必须在同一台机!!!
修改docker-compose配置和dockerfile
1. docker-compose.override.yml , 将volumes的代码注释去掉。改成下面这样的
1 2 3 4 5 6 7 8 9 10 11 12
|
version: '3.4' services: remote-debug-sample: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http: //0.0.0.0:80\ ports: - "5155:80" # enable local OS code watching and hot deployment volumes: - ./remote-debug-sample:/src/remote-debug-sample |
2. 修改Dockerfile.Develop,讲最后面的2段代码注释和去掉注释。修改后是这样的.
在这里需要特别注意2点:
目前的dotnet sdk image,不能用Debian的,我这里就改成5.0-focal,是使用Ubuntu的
最后的Entrypoint,必须要加上--no-launch-profile,否则,就会使用代码中的launchsetting,会导致asp.net不使用80端口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
FROM mcr.microsoft.com/dotnet/sdk:5.0-focal ARG BUILD_CONFIGURATION=Debug ENV ASPNETCORE_ENVIRONMENT=Development ENV DOTNET_USE_POLLING_FILE_WATCHER= true EXPOSE 80 WORKDIR /src COPY [ "remote-debug-sample/remote-debug-sample.csproj" , "remote-debug-sample/remote-debug-sample.csproj" ] RUN dotnet restore remote-debug-sample/remote-debug-sample.csproj # comment below lines to enable the coding watching # COPY . . # WORKDIR /src/remote-debug-sample # RUN dotnet publish --no-restore -c Debug -o /app # WORKDIR /app # ENTRYPOINT ["dotnet", "remote-debug-sample.dll"] # uncomment below lines to enable the coding watching WORKDIR /src/remote-debug-sample ENTRYPOINT [ "dotnet" , "watch" , "run" , "--no-launch-profile" ] |
重新构建Image和部署Container
1. 构建Image
1
|
docker-compose build |
2. 部署Container
1
|
docker-compose up |
配置远程VS code
1. 仿照上面的步骤,attach to containr, 安装VS code扩展,配置.net core attach调试文件
2. 启动调试,打断点。 这里我们需要选dotnet watch run的那一个

首先我们进入相同的地址(),可以看到json返回出来的还是hello,world!的字眼。

然后我们在本地代码修改,加入第11行的代码。需要注意的是,我们改的是本地文件!!

保存文件的改动!然后可以在Terminal下看到Application is shutting down... File changed, Started等提示,证明代码已经热部署了

我们再去浏览器看看结果,事实证明。 代码确实成功修改并且热部署了

停用调试和attach to container
其实有很多情况,我们是不需要调试的,只需要改代码做验证,那么就不需要attach to container和调试了。
只需要启动container,然后在本地修改你想改的代码,保存就能看到结果了。
结语
发现这篇文章写得非常的冗长,当作是新手指南吧。
因为当初我确实在这方面遇到了一点困难,所以觉得有必要详细分享。
不像网络上的都是几句话,附加到container,然后就调试。
还有什么坑我隐藏没有告诉你
首先我们要知道,调试的必要条件
1. 代码是用Debug发布的,或者Release发布后,必须包含*.pdb文件
2. 调试,我们需要的是sdk,而不是runtime
镜像的坑
1. 这次我也是首次调试.net5的代码,发现sdk:5.0的Image是有问题的,无法正常使用dotnet watch。后来我选择了用sdk:5.0-focal,就没问题了
2. 肯定有人好奇我一个这么简单的项目,为什么要用docker-compose。 其实原因是docker build要使用缓存会相对麻烦。所以我使用docker-compose,加快了每次生成Image的速度