-
Notifications
You must be signed in to change notification settings - Fork 568
02. How to containerize the .NET Framework web apps with Windows Containers and Docker
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.
Demonstrate several alternatives on how to containerize an existing .NET Framework application:
- Containerize your application through Visual Studio 2022 Tools for Docker (VS 2017 or later will work).
- Containerize your application by manually adding the dockerfiles and using the Docker CLI.
- 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.
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.
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:
- Windows 10 (For the developer machine)
- Docker for Windows (Docker CE for Windows)
- Visual Studio 2017, 2019, or 2022 (VS 15.6 or later)
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.
If the menu item says "Switch to Linux containers", you are already running Docker with Windows Containers.
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.
Then, in the next figure you can see how your project and solution has been modified with the Docker metadata.
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.
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.
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:
- Lab: Modernize .NET Apps - for Ops https://github.com/docker/labs/tree/master/dockercon-us-2017/windows-modernize-aspnet-ops
- Lab: Modernize .NET Apps - for Devs https://github.com/docker/labs/tree/master/dockercon-us-2017/windows-modernize-aspnet-dev
*** 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.
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.
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.
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
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
- Image2Docker PowerShell Module https://www.powershellgallery.com/packages/Image2Docker/
- Image2Docker official repo maintained by Docker https://github.com/docker/communitytools-image2docker-win
- Convert ASP.NET Web Servers to Docker with Image2docker https://blog.docker.com/2016/12/convert-asp-net-web-servers-docker-image2docker/
- Working with Windows Containers and Docker: Into your Stride https://www.red-gate.com/simple-talk/sysadmin/virtualization/working-windows-containers-docker-stride/
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.
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.
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:
- WCF Self-Hosted Services in a Container https://blogs.msdn.microsoft.com/webdev/2017/02/20/lets-try-wcf-self-hosted-services-in-a-container/
- How to: Install and Configure WCF Activation Components https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-install-and-configure-wcf-activation-components
- Home
- Release notes
- e-books
-
MVC & Web Forms Samples
- Tour of the "legacy" ASP.NET web apps to modernize
- How to containerize the .NET Framework web apps with Windows Containers and Docker
- Publishing your Windows Container images into a Docker Registry
- Deploying the Apps to Azure Web Apps for Containers
- Deploying the Apps to ACI (Azure Container Instances)
- Deploying your Windows Containers based app into Azure VMs (Including CI CD)
- Deploying into local Kubernetes in Windows 10 and Docker for Windows development environment
- How to deploy your Windows Containers based apps into Kubernetes in Azure Container Service (Including CI CD)
- How to add authentication authorization with Azure Active Directory
- How to migrate the SQL database to Azure with the Azure Database Migration Service
- Using Application Insights in eShopOnContainers
- N-Tier sample: WinForms app and WFC service
- ASP.NET to Azure App Service Migration Workshop