{"id":46632,"date":"2023-07-25T10:05:00","date_gmt":"2023-07-25T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=46632"},"modified":"2023-07-24T11:37:51","modified_gmt":"2023-07-24T18:37:51","slug":"debugging-dotnet-containers-with-visual-studio-code-docker-tools","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/debugging-dotnet-containers-with-visual-studio-code-docker-tools\/","title":{"rendered":"Debugging .NET Containers with Visual Studio Code Docker Tools"},"content":{"rendered":"<p>The Docker tools for Visual Studio Code has released version 1.26.0, bringing built-in support for building and debugging container images using the .NET SDK.<\/p>\n<h2>Docker Debugging in VS Code<\/h2>\n<p>The Docker tools for Visual Studio Code are a set of tools that make it easy for developers to get started with containers. It provides scaffolding of Dockerfiles, integrations to build, run and debug the containers generated from those Dockerfiles, and provides in-editor access to a number of other Docker- and Container-related tools. You can learn more about this tooling at the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-azuretools.vscode-docker\">Visual Studio Marketplace<\/a>.<\/p>\n<p>Previously, the Docker tools provided the ability to scaffold a Dockerfile for a .NET project. This Dockerfile looked something like this:<\/p>\n<pre><code class=\"language-dockerfile\">FROM mcr.microsoft.com\/dotnet\/runtime:8.0-preview AS base\r\nWORKDIR \/app\r\n\r\nUSER app\r\nFROM mcr.microsoft.com\/dotnet\/sdk:8.0-preview AS build\r\nARG configuration=Release\r\nWORKDIR \/src\r\nCOPY [\"MinimalApiSharp.csproj\", \".\/\"]\r\nRUN dotnet restore \"MinimalApiSharp.csproj\"\r\nCOPY . .\r\nWORKDIR \"\/src\/.\"\r\nRUN dotnet build \"MinimalApiSharp.csproj\" -c $configuration -o \/app\/build\r\n\r\nFROM build AS publish\r\nARG configuration=Release\r\nRUN dotnet publish \"MinimalApiSharp.csproj\" -c $configuration -o \/app\/publish \/p:UseAppHost=false\r\n\r\nFROM base AS final\r\nWORKDIR \/app\r\nCOPY --from=publish \/app\/publish .\r\nENTRYPOINT [\"dotnet\", \"MinimalApiSharp.dll\"]<\/code><\/pre>\n<p>This is a great foundation for building an efficient container image, but there&#8217;s a lot to understand out of the box. Users are immediately faced with understanding multi-stage Dockerfiles, container build args, and ensuring that paths align across stages for the build and publish outputs.<\/p>\n<h2>Building containers with the .NET SDK<\/h2>\n<p>Starting in .NET 7, the .NET SDK has had the ability to create container images easily via <code>dotnet publish<\/code>. With a single PackageReference (or no package at all if you&#8217;re using 7.0.300 or later SDKs!), a single <code>dotnet publish -p PublishProfile=DefaultContainer<\/code> command results in a working container image for your application. It has secure defaults out of the box, and lets users customize almost every aspect of the generated container.<\/p>\n<p>However, integrating these generated containers into tooling was a gap. This new version of the Docker tools for Visual Studio Code bridges that gap seamlessly &#8211; making it trivial to debug your containerized applications via the launch configuration mechanism in Visual Studio Code.<\/p>\n<h2>Bringing it together<\/h2>\n<p>Let&#8217;s take a look at what it takes to bring the SDK tooling and the Docker tooling together in VSCode.<\/p>\n<p>First, create a new web project using the .NET SDK and open it in Visual Studio Code. I&#8217;ll be using the .NET 8 preveiw 6 SDK here.<\/p>\n<pre><code class=\"language-shell\">&gt; dotnet new web -n MyContainerizedApp\r\nThe template \"ASP.NET Core Empty\" was created successfully.\r\n\r\nProcessing post-creation actions...\r\nRestoring D:\\Code\\Scratch\\MyContainerizedApp\\MyContainerizedApp.csproj:\r\nRestore complete (1.0s)\r\n\r\nBuild succeeded in 1.4s\r\nRestore succeeded.\r\n&gt; cd MyContainerizedApp\r\n&gt; code .<\/code><\/pre>\n<p>After the editor has launched, you should be able to press <code>F5<\/code> (or whatever key combination you&#8217;ve bound to the <code>workbench.action.debug.start<\/code> command) and get a selection menu much like the one below:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/07\/select-launch-method.png\" alt=\"select launch method dialog\" \/><\/p>\n<p>The key item to look for on this menu is the <code>Docker: Debug in Container<\/code> launch method. This launch method will build your app into a container, then automatically launch that container with the debugging tools attached! If you select it from this menu, you&#8217;ll see another important decision:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/07\/select-net-sdk.png\" alt=\"select net sdk\" \/><\/p>\n<p>This is where the new integration with the .NET SDK appears. If you select <code>Use a Dockerfile<\/code> here, then you&#8217;ll build the container with Docker according to a Dockerfile checked into your repo, but if you select the new <code>Use .NET SDK<\/code> option, the built-in containerization tooling in the .NET SDK will be used to build your container, then Docker will be used to run and debug that container.<\/p>\n<p>As soon as you choose the <code>Use .NET SDK<\/code> option, you should see the tooling building the container. It will appear in the task terminal (typically at the bottom of your editor window), and it&#8217;ll look something like this:<\/p>\n<pre><code class=\"language-text\">* Executing task: dotnet-container-sdk: debug\r\n\r\n&gt; dotnet publish --os \"linux\" --arch \"x64\" -p: PublishProfile=Defau1tContainer --configuration \"Debug\" -p:ContainerImageTag=dev\r\n&lt;\r\n\r\nMSBui1d version 17.7.0+5785ed5c2 for .NET\r\n Determining projects to restore...\r\n Restored d:\\Code\\Scratch\\MyContainerizedApp\\MyContainerizedApp.csproj (in 2.03 sec).\r\nC:\\Progran Files\\dotnet\\sdk\\8.0.100-preview.6.23330.14\\Sdks\\microsoft.NET.sdk\\targets\\microsoft.NET.Runtimeldentifierlnference.\r\ntargets(314,5): message NETSDK1057: You are using a preview version of .NET. \r\n  See: https:\/\/aka.ms\/dotnet-support-policy [d:\\Code\\Scratch\\MyContainerizedApp\\MyContainerizedApp.csproj]\r\n  MyContainerizedApp -&gt; d:\\Code\\Scratch\\MyContainerizedApp\\bin\\Debug\\net8.0\\linux-x64\\MyContainerizedApp.dll\r\n  MyContainerizedApp -&gt; d:\\Code\\Scratch\\MyContainerizedApp\\bin\\Debug\\net8.0\\linux-x64\\publish\\\r\n  Building image 'mycontainerizedapp' with tags dev on top of base image mcr.microsoft.com\/dotnet\/aspnet:8.0.0-preview.6<\/code><\/pre>\n<p>The terminal output here shows a few interesting things &#8211; the <code>dotnet publish<\/code> command used to build the container, as well as the MSBuild output sharing more about how the app container is being created.<\/p>\n<p>After a brief moment while the container is being built, the VSCode Docker tooling will launch the generated container, and additionally open a browser window pointing to your newly-launched application:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/07\/running-app.png\" alt=\"running app\" \/><\/p>\n<p>That was pretty easy, don&#8217;t you think? From here you can interact with the running container using all of the existing features of the Visual Studio Code Docker tooling.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>This is just the beginning for the integration between the Docker tooling for Visual Studio Code and the .NET SDK. Future enhancements to the SDK containers tooling will allow for automatically mapping ports from your SDK-generated containers, and the SDK containers team is looking to deepen the integration with Docker to allow for easier use with Docker Compose.<\/p>\n<p>If you&#8217;re not containinerizing your applications with the .NET SDK, we&#8217;d love to have you give that a try as well! You can learn more about how to <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/docker\/publish-as-container\">containerize a .NET app with <code>dotnet publish<\/code><\/a>, and then learn how to <a href=\"https:\/\/aka.ms\/dotnet\/containers\/customization\">customize the generated container<\/a>.<\/p>\n<p>Give the new features of the Docker Extension for Visual Studio code a try and let the team know <a href=\"https:\/\/github.com\/microsoft\/vscode-docker\/blob\/main\/SUPPORT.md\">what you think<\/a>, and if you have feedback for the .NET SDK Container tooling, make sure to visit the repo and <a href=\"https:\/\/github.com\/dotnet\/sdk-container-builds\/discussions\">start a discussion<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use the Docker extension for Visual Studio Code to build and run containerized .NET applications easily<\/p>\n","protected":false},"author":74549,"featured_media":46633,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7699,7689,7237,2904,7593],"tags":[57,60,63,7753],"class_list":["post-46632","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-dotnet-fundamentals","category-cloud-native","category-containers","category-docker","category-visual-studio-code","tag-containers","tag-docker","tag-dotnet","tag-vscode"],"acf":[],"blog_post_summary":"<p>Use the Docker extension for Visual Studio Code to build and run containerized .NET applications easily<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46632","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/74549"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=46632"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46632\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/46633"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=46632"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=46632"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=46632"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}