Write Dockerfile for traditional ASP.NET Apps (Part 2)
Ali Heydari
⏳ 7 min read
Introduction
In continuation of Part 1,
we will see how to write multi-staged Dockerfile for traditional ASP.NET apps with best practices. We will use a real world example.
Write Dockerfile
I decided to use a multi-stage Dockerfile to build the application.
The first stage is to build the application and the second stage is to run the application.
API Application (ASP.NET Web API)
As I mentioned in Part 1, The project contains a Web Application (ASP.NET MVC), A Web API (ASP.NET Web API) and a Windows Service (Console Application).
In this article, I will explain how to write a Dockerfile for the Web Application (ASP.NET Web API).
Many of the steps in the Dockerfile are the same for the Web Application. So If you read Part 1,
you can skip detailed steps and go directly to the final Dockerfile.
Step 1: Write builder stage
The first stage is to build the Web Application and Web API.
I used the mcr.microsoft.com/dotnet/framework/sdk:4.8 image to build the application.
Define the working directory and all needed arguments like credentials and build configuration.
Copy the solution file to the working directory.
Copy the packages.config and .csproj files to the working directory. before installing dependencies.
This will help Docker to cache the dependencies and speed up the build process.
(Optional) In that project I had to install the NuGet packages from a private repository. So I disabled the default NuGet repository and added the private repository.
If you don't have a private repository, you can skip this step.
Install the NuGet packages. you can combine this step with the previous step if you have a private repository to reduce the number of layers.
Copy the rest of the files to the working directory.
Let's cook!👨🍳 Build the project using MSBuild. (msbuild.exe is already installed in the base image)
Boom! We have a build! Now let's create the runtime image.
Step 2: Write runner stage
I used the mcr.microsoft.com/dotnet/framework/runtime:4.8-20220712-windowsservercore-ltsc2019 image as the base image for the runtime image.
In a Dockerfile, SHELL is an instruction that sets the default shell used for subsequent instructions.
In this case, it sets the default shell to PowerShell and passes two arguments to it: $ErrorActionPreference = 'Stop' and $ProgressPreference = 'SilentlyContinue'.
$ErrorActionPreference is a preference variable that determines how PowerShell responds to non-terminating errors.
Setting it to 'Stop' means that PowerShell will treat non-terminating errors as terminating errors, which will cause the script to stop running.
$ProgressPreference is another preference variable that determines how PowerShell displays progress information.
Setting it to 'SilentlyContinue' means that PowerShell will suppress all progress information.
Install the necessary Windows features, remove existing files, download ServiceMonitor.exe, and update the .NET Native Image Generator (NGEN)
Update SHELL to use PowerShell and pass only one argument to it: $ErrorActionPreference = 'Stop'.
Set the working directory to C:\inetpub\wwwroot.
Copy the build output from the builder image to the working directory.
Remove the default website and create a new website and application that listens on port 80.
Define the entry point for the container. The entry point is the command that is executed when the container starts.
In this case, the entry point is ServiceMonitor.exe,
which is an entrypoint process for running IIS in Windows containers.
Tada! We have a runtime image! Now let's create the final image.
The entire Dockerfile looks like this:
Build Dockerfile
First for building this images and running the container you need to have Docker installed on your machine if you don't have it you can download it from here.
Second you need to switch to Windows containers by right clicking on the Docker icon in the system tray and select Switch to Windows containers.
Now you only need to build your Dockerfile and tag it with a name. Here is the command to build the Dockerfile:
Run the container
Now you can run the container using the following command:
Test the container
Now you can test the container by navigating to http://localhost:8080 in your browser or calling the API using Postman.
You are done! I hope you enjoyed this tutorial. If you have any questions or comments please feel free to contact me.