前言

最近.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和简单的组件。

vscode 使用远程docker vscode远程docker调试_vscode

 

 

本地操作系统必要应用/工具

1. VS code, 版本尽量新,我用的是1.51.0版本,vs code从什么版本开始支持remote server确实不知道了。

2. VS code extension :Remote Development. 他是一个pack,会同时安装上container, WSL, SSH的远程调试扩展。 是下图这个样子的

vscode 使用远程docker vscode远程docker调试_vscode 使用远程docker_02

 

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。

等构建成功之后,会出现这种下图的这种提示

vscode 使用远程docker vscode远程docker调试_docker_03

3. 我们使用docker命令再次校验是否已经生成了我们想要的image

docker images | grep remote-debug-sample

vscode 使用远程docker vscode远程docker调试_remote debug_04

 

 

 

Container 跑起来

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

docker-compose up

vscode 使用远程docker vscode远程docker调试_vscode_05

 

 

 

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

 

vscode 使用远程docker vscode远程docker调试_vscode 使用远程docker_06

 

调试

Attach to Container

1. 从vscode的侧边栏点开Remote Explorer

然后这里能看到你的docker中有什么Container。 如果是第一次使用,在Other Containers下,如果已经曾经使用了,就会在Container下

vscode 使用远程docker vscode远程docker调试_vscode_07

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

vscode 使用远程docker vscode远程docker调试_vscode_08

 

3. 稍等几秒,就会自动打开一个新的vscode窗口。 (如果你在开始之前并没有安装前面提到的Remote Development 扩展组件,则这里需要等待几分钟去完成安装,然后才会打开新的vscode窗口)

等vs code窗口打开后,窗口的右下角会出现Starting Dev Container的提示,我们点击它,就会出现TermIcal的窗口

 

vscode 使用远程docker vscode远程docker调试_vscode_09

 

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

vscode 使用远程docker vscode远程docker调试_remote debug_10

 

 

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

vscode 使用远程docker vscode远程docker调试_docker_11

 

 

 

 

5. 我们再随便打开其中一个C# 文件,就会自动安装C# 调试不要的必要扩展了。其实这里可以通过自定义文件完成扩展的自动安装,不过这里不展开说.

如果没有自动安装,请自行安装

 

6. 等C#扩展安装好之后,在debug 的地方,按照平常本地使用vs code的方式,创建一个调试配置文件。

在调试窗内点击create a launch.json file.

vscode 使用远程docker vscode远程docker调试_docker_12

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

 

vscode 使用远程docker vscode远程docker调试_debug_13

 

 

然后配置文件就生成了,我们主要用里面的.NET Core Attach。 其余不需要的可以自行删除

{
    // 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

vscode 使用远程docker vscode远程docker调试_vscode_14

 

 

在HomeController的Index方法最后一行打上断点,打开http://localhost:5155/Home

稍等一会儿,就能看到已经进去断点了。

vscode 使用远程docker vscode远程docker调试_debug_15

我们需要的远程调试已经实现了

 

热部署和调试

其实在开发过程中,我们需要的很可能并不仅仅是调试,可能还需要修改代码。

那如果没改一次代码,都必须走完上面的全部步骤,那不是很坑吗。

所以我们需要引入dotnet watch 命令。

 

重点:但是要使用这种功能,container和代码必须要同一个台机!  前面的步骤都是能真正的远程调试,container可以运行在别的机器上。以下步骤必须在同一台机!!!

 

修改docker-compose配置和dockerfile

1. docker-compose.override.yml , 将volumes的代码注释去掉。改成下面这样的

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端口

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

docker-compose build

2. 部署Container

docker-compose up

 

配置远程VS code

1. 仿照上面的步骤,attach to containr, 安装VS code扩展,配置.net core attach调试文件

2. 启动调试,打断点。 这里我们需要选dotnet watch run的那一个

vscode 使用远程docker vscode远程docker调试_remote debug_16

 

 

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

vscode 使用远程docker vscode远程docker调试_vscode_17

 

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

vscode 使用远程docker vscode远程docker调试_docker_18

 

 

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

vscode 使用远程docker vscode远程docker调试_vscode 使用远程docker_19

 

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

vscode 使用远程docker vscode远程docker调试_debug_20

 

 停用调试和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的速度