Introduction
If you've ever used JetBrains Rider's built-in feature for debugging Docker and Docker Compose solutions, you may have found it works like a charm — or maybe not. I encountered issues with this feature where the debugger just wouldn't kick off. Unable to discern a pattern, I decided to investigate how Rider handles Docker Compose debugging under the hood. In this article, we'll walk through the setup, explore the commands Rider uses, dissect the generated Docker Compose file, and learn how to troubleshoot common issues.
Setting Up a Simple Web App Project
To understand how Rider's debugging works, I started by creating a basic C# web application. Below is the Dockerfile for the application.
# Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["Service1/Service1.csproj", "Service1/"]
RUN dotnet restore "Service1/Service1.csproj"
COPY . .
WORKDIR "/src/Service1"
RUN dotnet build "Service1.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Service1.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Service1.dll"]
The Docker Compose Configuration
I also created a docker-compose.yml
file and an override file, docker-compose.override.yml
, to manage the services.
# docker-compose.yml
version: '3.8'
services:
service1:
image: service1
build:
context: .
dockerfile: ./Service1/Dockerfile
service2:
image: service2
build:
context: .
dockerfile: ./Service2/Dockerfile
# docker-compose.override.yml
version: '3.8'
services:
service1:
ports:
- 8081:80
service2:
ports:
- 8082:80
Initiating Debugging in Rider
After configuring the Docker Compose setup in Rider, I clicked the "Debug" icon to initiate the debugging process.
Understanding the Command Rider Uses
Rider's approach diverges from what one might expect, which is the docker-compose up -f
command. If you take a look at the Service/Console window, you'll see the command Rider actually uses:
/usr/local/bin/docker compose -f /path/to/docker-compose.yml -f /path/to/docker-compose.override.yml -f /path/to/docker-compose.generated.override.yml -p project up -d
Note: I am using a Mac, so the file paths might differ on a Windows system.
Analyzing the Generated Docker Compose File
Rider generates an additional Docker Compose override file that provides crucial settings for debugging. Here's a simplified snippet:
# This is a generated file. Not intended for manual editing.
version: "3.8"
services:
service1:
build:
context: "/Users/marshinov/Work/tools/DockerDebug"
dockerfile: "./Service1/Dockerfile"
target: "base"
command: []
entrypoint:
- "/riderDebugger/linux-arm64/dotnet/dotnet"
- "/riderDebugger/JetBrains.Debugger.Worker.exe"
- "--mode=server"
- "--frontend-port=57100"
- "--backend-port=57300"
environment:
ASPNETCORE_ENVIRONMENT: "Development"
DOTNET_USE_POLLING_FILE_WATCHER: "true"
NUGET_PACKAGES: "/Users/marshinov/.nuget/packages"
NUGET_FALLBACK_PACKAGES: "/Users/marshinov/.nuget/packages"
RIDER_DEBUGGER_LOG_DIR: "/riderLogs"
RESHARPER_LOG_CONF: "/riderLogsConf/backend-log.xml"
image: "service1:dev"
ports:
- "127.0.0.1:57002:57100"
- "127.0.0.1:57202:57300"
volumes:
- "/Users/marshinov/.nuget/packages:/root/.nuget/fallbackpackages"
- "/Users/marshinov/Work/tools/DockerDebug/Service1:/app:rw"
- "/Users/marshinov/Work/tools/DockerDebug:/src:rw"
- "/Users/marshinov/.local/share/JetBrains/RiderRemoteDebugger/2023.2.1/LinuxArm64:/riderDebugger"
- "/Users/marshinov/Library/Application Support/JetBrains/Toolbox/apps/Rider/ch-0/232.9559.61/Rider.app/Contents/bin:/riderLogsConf"
- "/Users/marshinov/Library/Logs/JetBrains/Rider2023.2/DebuggerWorker/JetBrains.Debugger.Worker.2023_9_06_12_27_11:/riderLogs:rw"
working_dir: "/app"
service2:
build:
context: "/Users/marshinov/Work/tools/DockerDebug"
dockerfile: "./Service2/Dockerfile"
target: "base"
command: []
entrypoint:
- "/riderDebugger/linux-arm64/dotnet/dotnet"
- "/riderDebugger/JetBrains.Debugger.Worker.exe"
- "--mode=server"
- "--frontend-port=57100"
- "--backend-port=57300"
environment:
ASPNETCORE_ENVIRONMENT: "Development"
DOTNET_USE_POLLING_FILE_WATCHER: "true"
NUGET_PACKAGES: "/Users/marshinov/.nuget/packages"
NUGET_FALLBACK_PACKAGES: "/Users/marshinov/.nuget/packages"
RIDER_DEBUGGER_LOG_DIR: "/riderLogs"
RESHARPER_LOG_CONF: "/riderLogsConf/backend-log.xml"
image: "service2:dev"
ports:
- "127.0.0.1:57003:57100"
- "127.0.0.1:57203:57300"
volumes:
- "/Users/marshinov/.nuget/packages:/root/.nuget/fallbackpackages"
- "/Users/marshinov/Work/tools/DockerDebug/Service2:/app:rw"
- "/Users/marshinov/Work/tools/DockerDebug:/src:rw"
- "/Users/marshinov/.local/share/JetBrains/RiderRemoteDebugger/2023.2.1/LinuxArm64:/riderDebugger"
- "/Users/marshinov/Library/Application Support/JetBrains/Toolbox/apps/Rider/ch-0/232.9559.61/Rider.app/Contents/bin:/riderLogsConf"
- "/Users/marshinov/Library/Logs/JetBrains/Rider2023.2/DebuggerWorker/JetBrains.Debugger.Worker.2023_9_06_12_27_11:/riderLogs:rw"
working_dir: "/app"
This generated file performs several tasks:
- Attaches the Rider Remote debugger
- Overrides the original entry point to use the Rider Remote Debugger
- Ignores DLLs in the original image and uses source code mounted via volumes
- Opens additional ports for debugging
These changes are transformative, so much so that Rider essentially creates a completely different runtime environment, optimized for debugging.
Troubleshooting: The Issue I Faced
In my case, Rider ignored environment variables defined in my .env
file, which are usually considered by the docker-compose up -d
command. The COMPOSE_PROJECT_NAME
variable, in particular, led to confusion when toggling between standard Docker commands and Rider-based debugging. To resolve this, I had to explicitly specify the project name in Rider's Docker Compose settings.
Conclusion
After digging deep into how JetBrains Rider handles Docker Compose debugging, I've found a reliable workaround for the issues I was facing. Rider performs several substantial changes to your Docker Compose configurations to enable debugging, so understanding these can be key to troubleshooting effectively. I hope this deep dive saves you some time and helps you debug your applications more efficiently. Happy coding!
P.S. Visual Studio does a similar thing.
Top comments (0)