{"id":347071,"date":"2023-08-16T15:32:55","date_gmt":"2023-08-16T14:32:55","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=dotnet&#038;p=347071"},"modified":"2023-08-16T15:39:24","modified_gmt":"2023-08-16T14:39:24","slug":"debugging-docker-and-docker-compose-solutions-with-jetbrains-rider","status":"publish","type":"dotnet","link":"https:\/\/blog.jetbrains.com\/en\/dotnet\/2023\/08\/16\/debugging-docker-and-docker-compose-solutions-with-jetbrains-rider","title":{"rendered":"How To Debug Docker and Docker Compose Solutions with JetBrains Rider"},"content":{"rendered":"\n<p>Docker has become an integral part of a developer&#8217;s workflow, and <code>docker-compose<\/code> helps you build complex distributed solutions from your development to the production environment. In recent releases of JetBrains Rider, <a href=\"https:\/\/www.jetbrains.com\/rider\/whatsnew\/#version-2023-1-docker\" target=\"_blank\" rel=\"noopener\">we added <strong>Fast-Mode Docker Support<\/strong><\/a>. In short, your development feedback loop just got a lot faster.\u00a0<\/p>\n\n\n\n<p>We&#8217;ve noticed folks are still trying to understand this workflow, and we thought we&#8217;d write an updated walkthrough to help you debug both standalone container apps and <code>docker-compose<\/code> solutions. Let&#8217;s go ahead and get started.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Docker and Docker Compose?<\/h2>\n\n\n\n<p><a href=\"https:\/\/docker.com\" target=\"_blank\" rel=\"noopener\">Docker<\/a> is a containerization technology that allows you to package and deploy your application to a hosting destination. Containerization is a technique many vendors use, but Docker is the space&#8217;s most well-known commercial tooling provider, with 18 million developers using it worldwide.<\/p>\n\n\n\n<p>Core to Docker is the concept of containers. With containers, users can avoid common issues found with setting up environments. For example, container images can define dependencies, environment variables, and disk volumes through codification. In addition, a code-based configuration helps reduce common mistakes when manual processes are in place. While containerizing one application can be helpful, most modern solutions include several services talking to each other, and that&#8217;s where <code>docker-compose<\/code> comes in.<\/p>\n\n\n\n<p>Docker Compose is a tool to define multi-container applications through a carefully specified configuration. To start with, a <code>docker-compose<\/code> YAML file can use images defined by you or a third-party organization to orchestrate a distributed solution. In addition to containers, your environment definition can allocate shared resources, such as data volumes and networking. Docker Compose commands can also intelligently manage an environment, only recreating the changes in your solution. Finally, Docker Compose applies to all deployment environments, including CI\/CD pipelines.<br>To start with Docker, you&#8217;ll need an installed version of <a href=\"https:\/\/www.docker.com\/\" target=\"_blank\" rel=\"noopener\"><strong>Docker Desktop<\/strong><\/a> in your development environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rider and Docker Pre-flight Check<\/h2>\n\n\n\n<p>After installing Docker Desktop, you should check that Rider recognizes your Docker Desktop installation.&nbsp;<\/p>\n\n\n\n<p>First, start a new instance of JetBrains Rider and go to <strong>Settings <\/strong>and navigate to <strong>Build, Execution, Deployment | Docker. <\/strong>You should see that JetBrains Rider has recognized your installation of <strong>Docker Desktop. <\/strong>If you don&#8217;t see these settings, you likely don&#8217;t have the <strong>Docker <\/strong>plugin installed or enabled.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image.png\" alt=\"Settings dialog in JetBrains Rider showing Docker section\" class=\"wp-image-347072\" style=\"width:800px;height:623px\" width=\"800\" height=\"623\"\/><\/figure>\n\n\n\n<p>If you don&#8217;t see Docker in the settings window, ensure you have correctly installed <strong>Docker Desktop.<\/strong><\/p>\n\n\n\n<p>Next, you can open any existing project, and open the <strong>Services <\/strong>window. You should see the familiar Docker whale. You can connect to the Docker Desktop instance by double-clicking the whale icon. Once connected, you can see any running containers alongside images, networks, and volumes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image-1.png\" alt=\"Services window showing a disconnected Docker connection\" class=\"wp-image-347083\" style=\"width:544px;height:260px\" width=\"544\" height=\"260\"\/><\/figure>\n\n\n\n<p>If you do not see the Docker icon, click the &#8220;+&#8221; symbol and choose Docker Connection. At this point, you can add a new connection.<\/p>\n\n\n\n<p>Great. You should now be able to get started with .NET containerized development.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Debugging Docker containers with Rider<\/h2>\n\n\n\n<p>I&#8217;ll be using an <a href=\"https:\/\/asp.net\" target=\"_blank\" rel=\"noopener\">ASP.NET Core<\/a> solution with two web applications. When creating a new ASP.NET Core project, you&#8217;ll also have the chance to opt into <strong>Docker.<\/strong> Choosing Docker will add a <code>DockerFile<\/code> to your project.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image-2.png\" alt=\"Connected Docker connection in Services window\" class=\"wp-image-347094\" style=\"width:520px;height:525px\" width=\"520\" height=\"525\"\/><\/figure>\n\n\n\n<p>With a <code>DockerFile<\/code> open, you can run the container. Before running the container, you can edit the run configuration to expose the container ports to the host. You&#8217;ll need the ports exposed to the host environment to hit an API endpoint.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image-3.png\" alt=\"JetBrains Rider showing a Dockerfile for an ASP.NET Core project.\" class=\"wp-image-347105\" style=\"width:800px;height:572px\" width=\"800\" height=\"572\"\/><\/figure>\n\n\n\n<p>Now that your container is running, you can click the <strong>Debug <\/strong>button in the run toolbar. Furthermore, remember to add a breakpoint to see the debugger in action. Then, using the HTTP Client in Rider, you can call an endpoint to stop on your breakpoint.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image-4.png\" alt=\"Debugging a containerized ASP.NET Core application in Rider\" class=\"wp-image-347116\" style=\"width:800px;height:572px\" width=\"800\" height=\"572\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Debugging Docker Compose with Rider<\/h2>\n\n\n\n<p>JetBrains Rider recently added a feature to help define a <code>docker-compose.yml<\/code> file. JetBrains Rider will add each service to a central <code>docker-compose.yml<\/code> file with a straightforward right-click of any ASP.NET Core project and then selecting &#8220;<strong>Docker Compose file&#8221;.<\/strong><\/p>\n\n\n\n<p>I&#8217;ve added two ASP.NET Core web projects to a <code>docker-compose.yml<\/code> file, altering the ports in my orchestrated application. Then, by clicking the play button at the top of the file, we get a run configuration and the application containers running in the services window.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image-5.png\" alt=\"Docker Compose YAML file in Rider\" class=\"wp-image-347127\" style=\"width:800px;height:572px\" width=\"800\" height=\"572\"\/><\/figure>\n\n\n\n<p>You can now use the Debug button like debugging a single Docker container. Remember to set some breakpoints!<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/05\/image-6.png\" alt=\"Debugging a Docker Compose solution in Rider\" class=\"wp-image-347138\" style=\"width:800px;height:572px\" width=\"800\" height=\"572\"\/><\/figure>\n\n\n\n<p>You should see a debugging session tab for each service. In case of issues, you can use the Services window to confirm the following items.<\/p>\n\n\n\n<ul>\n<li>First, make sure your container has started. You could have a start-up exception that exits the process prematurely.<\/li>\n\n\n\n<li>Make sure the debugger ports exist on your container. These are typically in the range of <code>57000<\/code>.<\/li>\n\n\n\n<li>You see container environment variables for <code>RESHARPER_LOG_CONF<\/code> and <code>RIDER_DEBUGGER_LOG_DIR<\/code>. The presence of these variables ensures Rider successfully installed the debugger service into the container.<\/li>\n\n\n\n<li>Be sure a mounted volume of the<strong> RiderRemoteDebugger<\/strong> directory exists.<\/li>\n<\/ul>\n\n\n\n<p>If any of these items is missing, I suggest performing a <strong>Down<\/strong> action on your orchestration and rerunning the <code>docker-compose<\/code> file to recreate your solution within Docker Desktop.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Docker Compose Run Configuration labels<\/h2>\n\n\n\n<p>While fast mode is recommended for improving your development workflow, there are potential situations where you may want to disable it. For example, targeting the host operating system is essential when<strong> building artifacts using Ahead Of Time  (AOT) compilation<\/strong>. In the case of AOT, the compile-time environment must match the run-time one.<\/p>\n\n\n\n<p>Starting with Rider 2023.2, it is easier for you to fine-tune Docker Compose&#8217;s run configuration by introducing labels in your <code>docker-compose<\/code> files. By adding <code>labels<\/code> to the\u00a0<code>docker-compose.yml<\/code>\u00a0file, you can specify\u00a0<em>how<\/em>\u00a0and\u00a0<em>if<\/em>\u00a0you want to run and debug your applications.<\/p>\n\n\n\n<p>For example, if you want to disable fast mode for some of your services, you can set a&nbsp;<code>com.jetbrains.rider.fast.mode: \"false\"<\/code>&nbsp;label for each instance. If you want to disable debug mode, use the label&nbsp;<code>com.jetbrains.rider.debug: \"false\"<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1200\" height=\"785\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2023\/08\/image-4.png\" alt=\"A docker compose file with labels disabling fast mode.\" class=\"wp-image-379825\"\/><\/figure>\n\n\n\n<p>This has the added benefit of existing with your docker-compose file and getting the benefit of team-sharing and source control.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Debugging Docker containers and an orchestrated solution is straightforward with <a href=\"https:\/\/jetbrains.com\/rider\" data-type=\"URL\" data-id=\"https:\/\/jetbrains.com\/rider\" target=\"_blank\" rel=\"noopener\">JetBrains Rider<\/a>. As a result, users can benefit from containerization without losing the developer productivity of a debugger. If you are encountering issues debugging your containers, please double-check that you have set up your environment correctly, ports are exposed, and that Rider has installed the debugger services in your container. Also, ensure you&#8217;ve upgraded to the latest <a href=\"https:\/\/jetbrains.com\/rider\" target=\"_blank\" rel=\"noopener\">JetBrains Rider<\/a> and <a href=\"https:\/\/docker.com\/desktop\" data-type=\"URL\" data-id=\"https:\/\/docker.com\/desktop\" target=\"_blank\" rel=\"noopener\">Docker Desktop<\/a> versions.<\/p>\n\n\n\n<p>As always, thanks for reading, and let us know what you think in the comments below.<\/p>\n\n\n\n<p><sub><em>image credit: <a href=\"https:\/\/unsplash.com\/@thkelley\" target=\"_blank\" rel=\"noopener\">Thomas Kelley<\/a><\/em><\/sub><\/p>\n","protected":false},"author":1079,"featured_media":347150,"comment_status":"closed","ping_status":"closed","template":"","categories":[4992],"tags":[726,1040,1978],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/dotnet\/347071"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/dotnet"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/types\/dotnet"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/users\/1079"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/comments?post=347071"}],"version-history":[{"count":7,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/dotnet\/347071\/revisions"}],"predecessor-version":[{"id":381061,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/dotnet\/347071\/revisions\/381061"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media\/347150"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media?parent=347071"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/categories?post=347071"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/tags?post=347071"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/cross-post-tag?post=347071"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}