Skip to content
This repository has been archived by the owner on May 7, 2024. It is now read-only.

02. How to containerize the .NET Framework web apps with Windows Containers and Docker

Steve Smith edited this page Dec 14, 2021 · 13 revisions

Overview

Windows Containers should be used as a way to improve deployments to production, development, and test environments of existing .NET applications based on .NET Framework technologies like MVC, Web Forms or WCF.

Goals for this walkthrough

Demonstrate several alternatives on how to containerize an existing .NET Framework application:

  1. Containerize your application through Visual Studio 2022 Tools for Docker (VS 2017 or later will work).
  2. Containerize your application by manually adding the dockerfiles and using the Docker CLI.
  3. Containerize your application through Image2Docker tool (Open Source tool from Docker)

This walkthrough covers the three approaches although it offers further details for the VS 2017+ Tools for Docker approach.

Scenario: Containerize ASP.NET MVC or Web Forms apps

In this scenario you will containerize ASP.NET MVC or Web Forms apps (Traditional ASP.NET frameworks in .NET Framework 4.x).

The diagram below shows the scenario for the containerized eShop legacy applications running in a development PC with Docker for Windows.

docker for windows architecture diagram

But, under the covers, in order to run a container you need to create a Docker image and have it ready in your local Docker image repository. That is done under the covers by Visual Studio when you run it with F5 or Ctrl+F5:

image

Prerequisites

Containerizing your existing .NET applications with Visual Studio

Configuring Docker for Windows to use Windows Containers instead of Linux Containers

Before you run the solution, you must make sure that you configure Docker to use Windows Containers. To do that, you right-click the Docker taskbar icon in Windows and select Switch to Windows Containers, as shown in the figure below.

configure docker to use Windows containers

If the menu item says "Switch to Linux containers", you are already running Docker with Windows Containers.

Using Visual Studio to add Docker support to the application

You can do the following steps by adding "Add Docker Support" to the baseline eShopLegacyMVCSolution, for instance, by pulling that project into your machine and opening the eShopLegacyMVC.sln solution.

Visual Studio provides great support for containerizing an application. You right-click the project node and then select Add and Docker Support. The Docker project template adds a new project to the solution called docker-compose. The project contains the Docker assets (simple .yml metadata files) that comprise the Docker images and containers' startup settings you need, as shown in the figure below.

Visual Studio menu > Add > Docker Support

Then, in the next figure you can see how your project and solution has been modified with the Docker metadata.

docker-compose.yml file

In the simplest monolithic scenarios like this one, the application will be a single application service/container defined at the docker-compose.yml file that you will need to deploy. In other more complex scenarios like N-Tier applications, you will have a multi-container application defined in the docker-compose.yml file.

The template also changes your startup project to point to the docker-compose project so it will run on Docker when launching the solution. Pressing Ctrl+F5 or F5 now compiles the .NET application bits, creates the Docker image, and launches the Docker container all in a single step for you, as shown in the next image.

containerized app now running in Docker from Visual Studio

When VS is building the Docker image the first time you do this, it takes some time (a few minutes). This is because the build process pulls down the base Windows Server Core image and the additional image for ASP.NET. Subsequent build and run cycles will be much faster, since these image files are cached locally.

Let's take a deeper look at the files added by the Docker project template. It created several files for you. Visual Studio uses these files to create the Docker image and launch a container. You can use the same files from the CLI to run Docker commands manually with the Docker CLI commands like docker run and docker-compose up.

For each application or service in your solution Visual Studio adds a dockerfile to your project's root folder, similar to the following Dockerfile example showing the basic settings for building a Docker image based on the Windows ASP.NET image that runs an ASP.NET site.

Sample Dockerfile:

FROM microsoft/aspnet  
ARG source  
WORKDIR /inetpub/wwwroot  
COPY ${source:-obj/Docker/publish} . 

If your application were based on an older version of .NET Framework, like .NET Framework 3.5, you could use a similar base image directive like the following.

FROM microsoft/dotnet-framework:3.5

This previous Dockerfile will look very similar to those created for running an ASP.NET Core application in Linux containers. However, there are a few important differences. The most important difference is that the base image is microsoft/aspnet, which is an image based on Windows Server Core image that includes IIS, the .NET Framework and special optimizations for ASP.NET.

The other files in the docker-compose project are the Docker assets needed to build and configure the containers. Visual Studio puts the various docker-compose.yml files under one node (project) to highlight how they are used. The base docker-compose file contains the directives that are common to all configurations/environments. The docker-compose.override.yml file contains environment variables and related overrides for a by-default developer configuration.

Development and production environments

There are a couple of differences between the development configuration and a production configuration. In the development environment, you run the ASP.NET application and SQL Server in Windows Containers, within the same Docker host. In earlier sections, we mentioned that for development environments you could use a SQL localdb within the same application Windows Container or deploying an independent SQL Server Windows Container.

The advantage of running the database along with the multiple application containers within the same Docker host (or even orchestrator cluster looking forward) is that you have a very predictable testing environment with a consistent database that can have the same pre-generated data generated when deploying to the testing environment in the Docker host.

In the development environment, you usually run all the containers in the same environment, including the SQL databases, so it'll be easier while developing and testing.

In a production environment, you can decide if you want to run the application Windows Container in a single Docker host Azure VM, or in an orchestrator’s cluster like Service Fabric, and most of all, you will usually have the data stored in a high-available and production ready SQL environment like Azure SQL Database or Azure SQL Database Managed Instance.

Additional resources:

*** Optional finish of the walkthrough *** At this point you already containerized the application. The next sections focus on alternative approaches and more advanced scenarios you might need and you can also explore.

Containerizing your existing .NET applications with the Docker CLI and manually adding dockerfiles

While Visual Studio integration is part of adding Docker support to your solution, annd just by running the dockerized application with VS you are already creating the Docker images and deploying the containers in Docker, all in a single step ("F5 experience"), you can also containerize your application by manually adding the dockerfile and docker-compose files to your solution and then building the Docker images with the “docker build” CLI command and finally running the application from the command line, using the “docker-compose up” command or the “docker run command” as you can explorer in other Docker guidance like the “Containerized Docker Application Lifecycle with Microsoft Platform and Tools” eBook.

In order to generate your application's .NET bits, you can do so from VS and the menu option "Publish", then with the option "to folder" as used in this other Wiki procedure.

As an alternative option, in order to build the .NET bits from the CLI or from a CI pipeline, you need a build container or Docker build agent that will be internally using MSBuild to compile your .NET code. You can explore this walkthrough on "How to create a custom image for a .NET Framework build container internally using MSBuild".

Once you produced the .NET bits of your application, ready for you, in a directory, you’d build the Docker images with the CLI command “docker image build”, also explained in the same article/walkthrough.

Containerizing your existing .NET applications with Image2Docker

Another way to migrate existing .NET application from Windows VM running IIS towards Windows Containers, without using a developer tool like Visual Studio, is to use Image2Docker, an open-source tool originally created and provided by Docker (the company).

In this case you don’t even need to see the code or open any solution like when using Visual Studio and it has the advantage of having a tool that explores existing installation and configuration in Windows and will generate the dockerfile config for that specific configuration.

What is Image2Docker?

Image2Docker is basically a PowerShell module that migrates existing Windows application from VMs to Windows Container images. Although it supports multiple application types, the main focus is on IIS. You can use Image2Docker to export ASP.NET websites from a VM, so you can run them in a Windows Container with no application changes.

Requirements for Image2Docker:

  • Windows Server 2016
  • Windows 10 with Docker for Windows installed
  • PowerShell 5.0, or later

How does Image2Docker work?

Image2Docker first inspects the artifacts in a Windows Server VM image. This original VM could be a Windows Server 2003, 2008, 2012 or 2016 and its VM format could be WIM, VHD or VHDX.

Image2Docker will extract either an entire VM or specific components from a VHD file. Next, it will generate a Dockerfile which you can build into a Windows Container image.

For instance, if you have a VM disk image (VHD, VHDX or WIM), you can extract all the IIS websites from it by installing Image2Docker and running ConvertTo-Dockerfile like this:

`Install-Module Image2Docker
Import-Module Image2Docker
ConvertTo-Dockerfile -ImagePath C:\my-windows-2016.vhd -Artifact IIS -OutputPath c:\docker\W216iis`

That will produce a Dockerfile which you can use to build a Windows container image, using docker build.

Image2Docker, as of mid-2017, currently supports discovery of the following Windows artifacts:

  • Microsoft Windows Server Roles and Features
  • Microsoft Windows Add/Remove Programs (ARP)
  • Microsoft Windows Server Domain Name Server (DNS)
  • Microsoft Windows Internet Information Services (IIS)
  • HTTP Handlers in IIS configuration
  • IIS Websites and filesystem paths
  • ASP.NET web applications
  • Microsoft SQL Server instances
  • Apache Web Server

Additional resources for Image2Docker

Installing custom dependencies within your Windows Containers

In many cases, your existing .NET applications are not based just on your .NET code solution and the .NET Framework libraries but also based on additional artifacts from Windows that have to be enabled (IIS, .NET WCF HTTP Activation, Server roles, etc.) and even additional components from third parties that you need to install in windows through .MSI setups. You can perform those steps in a declarative way within the declared commands within your dockerfiles.

Installing MSIs in Docker images

In order to install an MSI within a Windows Container you just need to copy in the .msi file and run msiexec to install it. For instance, the following dockerfile specifies how to install a .msi in your container.

`# escape=`
FROM microsoft/aspnet:windowsservercore
COPY MySetupSample-1.0.0.0.msi /
RUN msiexec /i c:\ MySetupSample-1.0.0.0.msi RELEASENAME=2017.01 /qn `

There are just three lines of Dockerfile instructions:

  • FROM specifies the base image to use, in this case a specific version of the ASP.NET image using Windows Server Core.
  • COPY copies the existing MSI from the local machine into the Docker image
  • RUN installs the MSI using msiexec, with the qn switch to install silently, and passing a value to the custom RELEASENAME variable that the MSI uses.

That .msi setup could install whatever dependency you might need for your application, like the .DLLS of a PDF creator library (or any other comparable case) that you might need to use from your ASP.NET application.

You can also, of course, add these steps to your previous dockerfile so you may end up with multiple COPY commands (your application plus additional .MSIs) and therefore you could also execute multiple RUN commands from your dockerfile.

Enabling Windows features in Docker images

In order to enable Windows features or artifacts (like .NET WCF HTTP Activation, IIS configuration, etc.) in a Windows Container, you need to specify those dependencies in your dockerfile so they will be installed when the container is deployed.

For instance, the following dockerfile would enable .NET WCF HTTP Activation in your Windows Container:

`# Base image is Windows Server Core image since WCF does not need ASP.NET
FROM microsoft/windowsservercore

RUN powershell -Command Add-WindowsFeature NET-WCF-HTTP-Activation45

# Creates a directory for the Host
WORKDIR app
# Listen on port 88.
EXPOSE 88
# Copy the WCF host into the container.
COPY Bin/ .
ENTRYPOINT BasicHttpHost.exe`

The important line in that dockerfile is the line with the RUN command that specifies to add certain Windows Feature, in this case, .NET WCF HTTP Activation. Note that not all the Windows features can be activated in Windows Containers since some of them are not supported, like MSMQ or other cases.

Other supported cases for Windows Containers can be the following:

  • Like ISAPI handler in IIS.
  • A .PDF creation service program installed with a .MSI.
  • Office Automation.
  • ASP.NET Controls.
  • IIS enable and configured.
  • WCF HTTP Activation – Program – Windows Settings (Kind of IIS activation)
  • List of dockerfiles with many dependencies and settings being configured.
  • Have .NET 3.5 in the Docker image.

Additional resources:

Clone this wiki locally