Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker .NET Core Attach: Multiple processes were found matching the process name. Attach by process id instead. #2248

Closed
MarcusOy opened this issue Aug 22, 2020 · 15 comments · Fixed by #2295
Labels
Milestone

Comments

@MarcusOy
Copy link

MarcusOy commented Aug 22, 2020

Hi there,

I am trying to use the templated "Docker .NET Core Attach (Preview)" launch config, however, it is not working correctly after pressing run and selecting a running container (for any of my .NET Core projects); it results in the error: "Multiple processes were found matching the process name. Attach by process id instead." The logical next step was to use a process id picker, which resulted in asking me for both a container name and process id but still resulted in an error: "Must specify either processId or processName." I'm not really sure what to do, as I've followed many tutorials to try and get debugging to work on my .NET Core containers but this launch config seemed to be the closest to actually working. Below is the launch config just in case:

        {
            "name": "Docker .NET Core Attach (Preview)",
            "type": "docker",
            "request": "attach",
            "platform": "netCore",
            "sourceFileMap": {
                "/src": "${workspaceFolder}"
            },
            "processId":"${command:pickProcess}"
        },

I've also heard from the docs that this launch config may be deprecated already, and in that case, what is listed on the docs also doesn't work for me (something about it not finding the listed task on the docs). Many thanks in advance for advice.

Best regards,
Marcus

Version: 1.5.0
OS: ubuntu
OS Release: 20.04 LTS
Product: Visual Studio Code
Product Version: 1.48.1
Language: en

@bwateratmsft
Copy link
Collaborator

bwateratmsft commented Aug 25, 2020

@MarcusOy This one is not deprecated--the "type": "docker-coreclr" one is. We'll take a look at this.

MarcusOy added a commit to MarcusOy/vscode-docs that referenced this issue Aug 25, 2020
In VSCode, creating a new launch config within launch.json with the template name Docker: .NET Core Attach (Preview) will create a config listed in the .NET Core section. I believe the quote saying "previous (Preview)" is deprecated is ambiguous, since the documentation doesn't say that the current version of the config available as a launch config template is still labeled as a preview. This let me to believe that the config I had added within my launch.json was the deprecated implementation.

I propose this simple change to clear up my original confusion.
See comment: microsoft/vscode-docker#2248 (comment)
@bwateratmsft
Copy link
Collaborator

@MarcusOy It seems like there must be more than one dotnet process running in the container, hence the confusion. The ${command:pickProcess} flag would choose a process on the host, not in the container, if I'm not mistaken.

Do you know why there might be multiple dotnet processes running?

@MarcusOy
Copy link
Author

MarcusOy commented Aug 27, 2020

@bwateratmsft Huh, that's weird. I checked Portainer to see the running processes on my affected containers and there's three total dotnet processes. My setup is currently a few development containers running on watch mode, so maybe that is the cause. Here's an image from Portainer of the processes:
Screen Shot 2020-08-27 at 5 20 55 PM

The container is spun up from a dev docker image, last Dockerfile statement is:

ENTRYPOINT dotnet watch run --urls=http://*:5000

I am using docker-compose, but I have no additional additional command going to any services containing any of my dotnet core dev images.

Would I need to somehow select the container's PID or is having multiple dotnet processes very wrong in either a dev or prod container? I'm still very new to docker, so I am trying to learn the ropes.

Edit: Only 2 dotnet processes, the last one is the dotnet-watch process.

@bwateratmsft
Copy link
Collaborator

I wouldn't say wrong, just different. I'm not terribly familiar with dotnet watch, but the first one is /bin/sh (with a command to do dotnet watch), the second is what is started by that sh command, and I think the third is what is started by dotnet watch run process (i.e. the app itself). So the second two in that list are both dotnet processes.

Given that this is in a dev container it is may be easier to make use of Remote - Containers, by attaching VSCode to the container and then debugging as if it was locally. The debugging in the Docker extension is a bit more like "production" debugging, in that you're debugging an app as it would run in its runtime container image. The line between these scenarios is definitely blurry though.

I found another approach that almost worked; the C# extension offers a substitute for ${command:pickProcess} (namely, ${command:csharp.listRemoteProcess}). This is smart enough to go through the pipe program (docker exec) to get processes from the remote "machine", not locally. Unfortunately, it doesn't work on Debian images because ps is not present, and it doesn't work on Alpine images because the -x flag used in the ps command is not recognized. I opened this issue in the C# repo about that.

@MarcusOy
Copy link
Author

MarcusOy commented Sep 2, 2020

@bwateratmsft I've been working on other things and I've revisited this issue. I am able to connect to my container using the following config (from OmniSharp's docs):

        {
            "name": "Portal Attach",
            "type":"coreclr",
            "request":"attach",
            "processId": "${command:pickRemoteProcess}",
            "pipeTransport": {
                "pipeProgram": "docker",
                "pipeArgs": [ "exec", "-i", "locorumportal" ],
                "debuggerPath": "/vsdbg/vsdbg",
                "pipeCwd": "${workspaceRoot}/xxx.Web/",
                "quoteArgs": false
            },
            "sourceFileMap": {
                "/app": "${workspaceRoot}"
            }
        },

Now, since this config is beyond the scope of this issue's repo, I'm gonna go ahead and close it. Now, to figure why my symbols aren't loading properly...

@MarcusOy MarcusOy closed this as completed Sep 2, 2020
@bwateratmsft
Copy link
Collaborator

Yeah, that config with pipeTransport is very similar to what we ultimately resolve to in the Docker .NET Core Attach config.

@MarcusOy
Copy link
Author

MarcusOy commented Sep 5, 2020

@bwateratmsft Reopening.

I am going to attach a test project for you to try: test.zip
It contains a solution with one Web API project. At root is a docker-compose.yml and inside the project (test.API) is a Dockerfile. Run a restore, clean, build or whatever then run docker-compose up in the workspace root to start up the project. This has been tested on two of my machines: a Ubuntu 20.04 desktop and a MacOS Catalina Macbook.

Notice two configs in the launch.json: a Docker config and a CoreCLR config.

Obviously, with the Docker config, when run it prompts you to pick a container, then asks to copy over the debugger. Even when taking out references to dotnet watch, the "Multiple Processes..." error occurs, but that's not a problem: kill the attached shell, run docker-compose down then docker-compose up and try again. I "successfully" connect the debugger, except it didn't. Symbols for my main module have not loaded and by executing a controller route with the statement System.Diagnostics.Debugger.IsAttached, we see that it evaluates to false. My prediction is that the debugger isn't attaching into the right process, perhaps attaching to another dotnet process. I looked for a way to find what pid the debugger is attaching to, but I haven't found anything at a casual glance, so no way for me to know exactly.

Meanwhile, the other config gives more control as I can now pick a process on the remote container. I've noticed that you must select the process with the project's full name. For example:
image
When selecting test.API from the list, symbols are loaded for the main module, debugger is attached as System.Diagnostics.Debugger.IsAttached is now true, and breakpoints are being evaluated.

Why am I reopening this issue? One of the first results for debugging a dotnet core docker container using VSCode. I think it's crucial for those just starting to use dotnet with docker and VSCode are able to find the solution/configuration they need without spending a huge amount of research just to get a test project to debug. Perhaps advertise the CoreCLR config using pipeTransport over the current config on that page? Maybe create an option for the config to also have a remote process picker? Not trying to be a pain or anything, I just want you guys to have my experiences in trying to get my environment to work and to improve the product for everyone.

@MarcusOy MarcusOy reopened this Sep 5, 2020
@PavelSosin-320
Copy link

@MarcusOy Thre is the special way in docker to handle processes; docker container top. It is someway different that ps inside the container. It shows PIDs of the daemon host system PIDs, the Daemon protects Container's processes in isolation purposes and Container init observers them to avoid ghost and zombie host processes. Hopefully, the Process picker takes this mechanism into account correctly Marcus, could you attach the docker container top output at the time when you try to attach to it to the issue?.

@josiah-roberts
Copy link

✋ Also having this issue. I started out with the non-compose way of using a sequence of tasks to start the docker container, but that seemed to have assumptions baked into it regarding the command line (non-watch). Composing-up the container allows me to run it in watch, but I've been unable to debug.

@PavelSosin-320
Copy link

There is always the best practice in the docker is to start all processes from the entry script. It is an immediate child of the docker init process and easily observable by the daemon. It ensures that the container will never see underlying host processes -isolation, and the correct lifecycle management - killed container cleans up. I afraid that dotnet watch may create sibling process which is unknown to the init, i.e. to docker daemon. This situatio should never happen.
For the safe networking every container shall expose its port to the the certain docker network. The IPC inside container using localhost is not a good practice too. There is no network is created inside container because it is not a VM. Docker daemon offers network to every container by demand, bridge is the default. I didn't see a network definition in the compose-file.

@PavelSosin-320
Copy link

Regarding debugging: what is the debuggee,S tandalone DotNet application or Docker container DotNet application? In the 1st case the corresponding VSCode DotNet debugger plugin should be used. In the second case the application container has to be built from Official Microsoft DotNet DotNet Docker containers documentation . In any case DotNet core wired debugger protocol uses TCP ports 4024 and 4025. Debuggee must expose one of these ports. This port will be exposed via bridge network to the cient applications running on the host or network, debugger for example.

@MarcusOy
Copy link
Author

MarcusOy commented Sep 5, 2020

Thank you for your response @PavelSosin-320. Here's my docker top output. For your references, I've run the command twice:

  • The first time is with entry point ENTRYPOINT dotnet run --urls=http://*:5000 in the Dockerfile for test.API
  • The second time is with entry point ENTRYPOINT dotnet watch run --urls=http://*:5000 in the Dockerfile for test.API

Screen Shot 2020-09-05 at 3 29 29 PM

I would like to just reiterate: I am able to get debugging to work against a remote container running a dotnet project (WITH and WITHOUT watch) using the CoreCLR attach launch.json config. I will paste it below so that others can retrieve it without hassle:

{
        "name": "Test Attach",
        "type":"coreclr",
        "request":"attach",
        "processId": "${command:pickRemoteProcess}",
        "pipeTransport": {
            "pipeProgram": "docker",
            "pipeArgs": [ "exec", "-i", "testapi" ], // Change to container name
            "debuggerPath": "/vsdbg/vsdbg",
            "pipeCwd": "${workspaceRoot}/test.API/", // Change to project location
            "quoteArgs": false
        },
        "sourceFileMap": {
            "/app/test.API": "${workspaceRoot}/test.API", // Change to project location
        }
}

This config will work assuming you have copied the vsdbg into your image using Dockerfile like this:

...
WORKDIR /vsdbg

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
            unzip \
    && rm -rf /var/lib/apt/lists/* \
    && curl -sSL https://aka.ms/getvsdbgsh \
        | bash /dev/stdin -v latest -l /vsdbg
...

BTW, I am using mcr.microsoft.com/dotnet/core/sdk:3.1.

With that being said, it doesn't look like I have to change any docker-compose networking settings, the default bridge seems to be doing ok.

@PavelSosin-320
Copy link

PavelSosin-320 commented Sep 6, 2020 via email

@bwateratmsft
Copy link
Collaborator

I've wanted for a long time to have a real debugging experience using docker-compose but the powers that be haven't prioritized it (#840). The debugging tasks and config we have now work well for single-project, non-compose scenarios but start to break down when compose is mixed in.

@bwateratmsft
Copy link
Collaborator

@MarcusOy I spent some time playing with that test project you provided. I made a few small changes in the Dockerfile:

  1. Set the default path for the debugger to /remote_debugger, which will prevent the extension from needing to copy in vsdbg
  2. Changed the entrypoint style. This makes it not start a shell process and "fixes" the multiple dotnet processes problem (but then the C# extension goes ahead and attaches to the wrong process--the outer dotnet one--which causes it to not load symbols for your app, because it's not actually in that process).
FROM mcr.microsoft.com/dotnet/core/sdk:3.1

WORKDIR /remote_debugger # Changed from /vsdbg

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
            unzip \
    && rm -rf /var/lib/apt/lists/* \
    && curl -sSL https://aka.ms/getvsdbgsh \
        | bash /dev/stdin -v latest -l /remote_debugger # Changed from /vsdbg

WORKDIR /app
COPY ./test.sln ./
# COPY ./test.API/ ./test.API/

ENV DOTNET_USE_POLLING_FILE_WATCHER 1
ENV DOTNET_CLI_TELEMETRY_OPTOUT 1

WORKDIR /app/test.API

# ENTRYPOINT dotnet watch run --urls=http://*:5000
ENTRYPOINT ["dotnet", "run", "--urls=http://*:5000"] # Changed from line like above

# ----------------------------------------------------------

After launching and resolving the Docker attach configuration, this is what it resolves to:

{
    "name": "Docker .NET Core Attach (Preview)",
    "type": "coreclr",
    "request": "attach",
    "platform": "netCore",
    "sourceFileMap": {
        "/app/test/API": "${workspaceRoot}/test.API"
    },
    "justMyCode": false,
    "processName": "dotnet",
    "pipeTransport": {
        "pipeProgram": "docker",
        "pipeArgs": [
            "exec",
            "-i",
            "testapi"
        ],
        "pipeCwd": "${workspaceFolder}",
        "debuggerPath": "/remote_debugger/vsdbg",
        "quoteArgs": false
    }
}

The only significant difference between this config and the coreclr one you provided is processName instead of processId. I tried putting in "processId": "${command:pickRemoteProcess}", which almost works except it results in both processName and processId being passed to the C# extension which results in an error. This may have worked in the past--there's a comment in the Docker extension's code suggesting it did--but it certainly doesn't now. So that's one thing to fix here separate from #840. Alternatively, adding "processName": "test.API" into the Docker attach config works without needing to use processId:

        {
            "name": "Docker .NET Core Attach (Preview)",
            "type": "docker",
            "request": "attach",
            "platform": "netCore",
            "processName": "test.API",
            "sourceFileMap": {
                "/app/test/API": "${workspaceRoot}/test.API"
            }
        },

Ultimately though, what is really needed here is #840. I'll use this issue to track fixing the processId / processName thing but I'd encourage you to comment on #840 to push for it. 😄

@bwateratmsft bwateratmsft added this to the 1.7.0 milestone Sep 11, 2020
@vscodebot vscodebot bot locked and limited conversation to collaborators Oct 26, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants