It’s been a year since I wrote the original tutorial on how to debug .NET Core apps from Visual Studio 2017. Now I do use VSCode even for .NET debugging so I decided to write a new post about this.

Let’s assume that you have a workspace folder with the following structure:

Root Workspace Folder

+-- Dockerfile

`-- app

+-- App.csproj

`-- ...

With this assumption we can write the first build stage in the Dockerfile like this:

FROM microsoft/dotnet:2.1-sdk as dotnet-build

ARG DOTNET_CONFIG=Release

WORKDIR /build

COPY /app/*.csproj ./

RUN dotnet restore

COPY /app/ .

RUN dotnet publish -c ${DOTNET_CONFIG} -o ./results

Here we first copy only App.csproj file and restore dependencies in order to cache this layer and skip it if there are no changes in dependencies since the last build. Remember that we put all the code into /build folder — we will need it later to specify source code mappings.

Next step is to write the final stage of the image build:

FROM microsoft/dotnet:2.1-aspnetcore-runtime as app

ARG INSTALL_CLRDBG=exit

RUN bash -c "${INSTALL_CLRDBG}"

WORKDIR /app

EXPOSE 80

COPY --from="dotnet-build" /build/results .

ENTRYPOINT ["dotnet", "App.dll"]

In lines 2–3 we provide a way to later specify debugger installation script from docker build command. Finally we copy build results from dotnet-build stage and specify entry point.

Let’s build this image with the following shell script:

IMAGE=your-registry/your-app-image;

docker build -t $IMAGE \

--build-arg DOTNET_CONFIG=Build \

--build-arg INSTALL_CLRDBG="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" \

.;

docker push $IMAGE;

You have to replace your-registry/your-app-image with the real value. In docker build command we specify configuration for dotnet publish command to be Build and override debugger installation script. In production you would skip those --build-arg 's.

Next you can deploy this image into kubernetes cluster as you usually do but don’t forget to remove or adjust liveness/readyness probs. Or you can just run the following command to start a new pod:

kubectl run my-app --image=$IMAGE --labels="app=my-app"

In order to start debugging this new instance of our app we need to add the following shell script into the root workspace folder:

Next we need to adjust launch.json to use this script:

In sourceFileMap we specify /debug folder on the container side since we put all the source code into this folder during dotnet-build stage and ${workspaceRoot}/app on the host machine side since it’s the place of our original source code. In case of multiple dotnet projects we wouldn’t need to add /app at the end since dotnet would automatically add each project folder relative to the solution.

As a pipeProgram we use Git Bash (since we’re on Windows) and pass kube-debug.sh script which we created at the previous step. Next we specify the same --selector as a label we used in kubectl run command and optionally --namespace .

debuggerPath is relative to the WORKDIR /app since it works only this way on Windows otherwise Git Bash thinks that path is relative to the host machine. Don’t ask me why…

Now you can press F5 and enjoy debugging session!