Deploying ASP.NET 4.5 to Docker on Windows

At the moment of this writing you can search the internet on ASP.NET and docker and all you will find is how to deploy ASP.NET Core applications to a Linux docker container. Although I love the initiative of ASP.NET core, I do believe that ASP.NET 4.5 is something many of you know and love already and nobody talks about how we can leverage docker on windows to run this full version of ASP.NET

To get you started we need to have a Windows version that is capable of natively running docker. With natively running docker I mean that docker is build into the OS. So no use of docker for windows tools, since we don’t want Linux containers, we want to run windows containers! At this moment you can use Windows 10 Anniversary edition and Windows Server 2016 Technical Preview 5 to go through the steps that I describe here to get your ASP.NET 4.5 website running in a docker on windows container.

What do we need to rollout an ASP.NET website to a windows docker container?

When you run an ASP.NET 4.5 website then you need the following things:

The Operating system with IIS installed

ASP.NET 4.5 installed

Webdeploy installed

I personally love to use web deploy to deploy the website after build, so it can be done exactly the same way as you would deploy to Azure App Services or your local IIS Server on any server you already know and love.

Building the container with IIS, ASP.NET and Webdeploy

Here are the steps you need to take to create a docker container that has all these required ingredients:

Fist we need a basic operating system image from docker hub. For this you can run the following command from the command line:

<strong>docker pull microsoft/windowsservercore</strong> 1 < strong > docker pull microsoft / windowsservercore < / strong >

now we have the image in our images gallery, you can check this with the following command:

<strong>docker images</strong> 1 < strong > docker images < / strong >

This should output something similar to the following screenshot:

Now we can start adding the first layer and that is installing IIS. For this you can use the dism command on windows and pass it in the arguments to install the IIS webserver role to windows server core. You can do this at an interactive prompt or use the docker build command. I prefer the later and for this we create a dockerfile that contains the following statements:

<strong>FROM microsoft/windowsservercore <br> RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart</strong> 1 2 < strong > FROM microsoft / windowsservercore < br > RUN dism / online / enable - feature / all / featurename : iis - webserver / NoRestart < / strong >

After saving the file under the name dockerfile without any extensions you run a command line to build the image:

<strong>docker build -t windowsserveriis .</strong> 1 < strong > docker build - t windowsserveriis . < / strong >

The command tells docker to build an image, give it the tag windowsserveriis and use the current folder (denoted with the dot) as the context to build the image. this means that everything stated in the dockerfile is relative to that context. Note that you are only allowed to use lowercase characters for the tagename.

After running the command you now have a new docker image with the name windowsserveriis

If you now run the command:

<strong>docker images</strong> 1 < strong > docker images < / strong >

you will see the new image available

We can take the next step and that is to install ASP.NET 4.5

We can do this in a similar way, by creating a docker file with the following commands:

<strong>FROM windowsserveriis <strong>RUN dism /online /enable-feature /featurename:IIS-ASPNET45</strong> 1 2 < strong > FROM windowsserveriis < strong > RUN & nbsp ; dism / online / enable - feature / featurename : IIS - ASPNET45 < / strong >

and again after saving the file you can run the command line to build the image:

<strong>docker build –t windowsserveriisaspnet .</strong> 1 < strong > docker build – t windowsserveriisaspnet . < / strong >

Now we have an image that is capable of running an ASP.NET application. The next step is that we need webdepoy to be installed in the container. For this we need to download the installer for webdeploy and then issue an command that will install and wait for the installation to finish. We first download the installer in the same folder as the dockerfile and then we will add it to the image. In the following steps I assume you already downloaded the MSI (WebDeploy_2_10_amd64_en-US.msi) and have it in the same folder as the dockerfile. When installing the msi we will use msiexec and need to start a process that we can wait on to be done. If we would only run msiexec, then this command returns and runs in the background, making the container to exit, leaving us in an undefined state.

When you create the following dockerfile, you install webdeploy:

<strong>FROM windowsserveriisaspnet</strong> <p><strong>RUN mkdir c:\install</strong></p> <p><strong>ADD WebDeploy_2_10_amd64_en-US.msi /install/WebDeploy_2_10_amd64_en-US.msi</strong></p> <p><strong>WORKDIR /install</strong></p> <p><strong>RUN powershell start-Process msiexec.exe -ArgumentList '/i c:\install\WebDeploy_2_10_amd64_en-US.msi /qn' -Wait</strong></p> 1 2 3 4 5 < strong > FROM windowsserveriisaspnet < / strong > < p > < strong > RUN mkdir c : \ install < / strong > < / p > < p > < strong > ADD WebDeploy_2_10_amd64_en - US . msi / install / WebDeploy_2_10_amd64_en - US . msi < / strong > < / p > < p > < strong > WORKDIR / install < / strong > < / p > < p > < strong > RUN powershell start - Process msiexec . exe - ArgumentList '/i c:\install\WebDeploy_2_10_amd64_en-US.msi /qn' - Wait < / strong > < / p >

Note that we are using powershell start-process with the –wait option, so we wait for the installation to finish, before we commit the new layer.

Now run the docker command again to build the image using the new dockerfile:

<strong>docker build –t windowsserveriisaspnetwebdeploy .</strong> 1 < strong > docker build – t windowsserveriisaspnetwebdeploy . < / strong >

Now we have an image that is capable to host our website in IIS and use webdeploy to install our website.

Doing it all in one dockerfile

In the previous steps we created a new docker file for each step. But it is probably better to do this in one file, batching all commands together leaving you with the same endstate. We can also optimize the process a bit, since Microsoft already provides an image called microsoft/iis that has the iis feature enabled. This means we can use that image as the base layer and skip the install of IIS.

The simplified docker file looks as follows:

<strong>FROM microsoft/iis<br>RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart<br>RUN mkdir c:\install<br>ADD WebDeploy_2_10_amd64_en-US.msi /install/WebDeploy_2_10_amd64_en-US.msi<br>WORKDIR /install<br>RUN powershell start-Process msiexec.exe -ArgumentList '/i c:\install\WebDeploy_2_10_amd64_en-US.msi /qn' -Wait</strong> 1 < strong > FROM microsoft / iis < br > RUN dism / online / enable - feature / all / featurename : iis - webserver / NoRestart < br > RUN mkdir c : \ install < br > ADD WebDeploy_2_10_amd64_en - US . msi / install / WebDeploy_2_10_amd64_en - US . msi < br > WORKDIR / install < br > RUN powershell start - Process msiexec . exe - ArgumentList '/i c:\install\WebDeploy_2_10_amd64_en-US.msi /qn' - Wait < / strong >

Now again we run the docker build command to get the docker image capable of running our website and use the webdeploy packages that can be produced by a standard ASP.NET build procedure.

<strong>docker build –t windowsserveriisaspnetwebdeploy .</strong> 1 < strong > docker build – t windowsserveriisaspnetwebdeploy . < / strong >

The final step is to deploy your webdeploy package to the image.

Getting the webdeploy package

Now before we can deploy our website we need to get the webdeploy package.

I assume you have a standard ASP.NET web project in Visual Studio. In this case you can very easily create the deploy package inside Visual Studio (in the next post I show you how to do this using VSTS/TFS builds)

When you right click the Visual Studio project you can select the publish option:

After selecting publish you will see the following dialog:

In order to just create a package in stead of deploying to a server or Azure, I select Custom

then you give the profile a name, in my case dockerdeploydemo

then we select web deploy package from the dropdown and provide the required information, package location and the name of the website

next you can setup any database connections if you have any, in my case I have no database

next, click publish and you will find the resulting deployment package and accompanying deployment files in the c:\temp folder

Now that we have the webdeploy package and the accompanying deployment artifacts, we can again create a docker file that will then upload the package to the container and install the website in the container. This will then leave you with a complete docker image that runs your website.

Publish the website in the docker container

The dockerfile to deploy your website looks as follows:

<strong>FROM windowsserveriisaspnetwebdeploy </strong><p><strong>RUN mkdir c:\webapplication</strong></p><p><strong>WORKDIR /webapplication</strong></p><p><strong>ADD dockerdeploydemo.zip /webapplication/dockerdeploydemo.zip</strong></p><p><strong>ADD dockerdeploydemo.deploy.cmd /webapplication/dockerdeploydemo.deploy.cmd<br>ADD dockerdeploydemo.SetParameters.xml /webapplication/dockerdeploydemo.SetParameters.xml</strong></p><p><strong>RUN dockerdeploydemo.deploy.cmd, /Y</strong></p> 1 < strong > FROM windowsserveriisaspnetwebdeploy < / strong > < p > < strong > RUN mkdir c : \ webapplication < / strong > < / p > < p > < strong > WORKDIR / webapplication < / strong > < / p > < p > < strong > ADD dockerdeploydemo . zip & nbsp ; / webapplication / dockerdeploydemo . zip < / strong > < / p > < p > < strong > ADD dockerdeploydemo . deploy . cmd / webapplication / dockerdeploydemo . deploy . cmd < br > ADD dockerdeploydemo . SetParameters . xml / webapplication / dockerdeploydemo . SetParameters . xml < / strong > < / p > < p > < strong > RUN dockerdeploydemo . deploy . cmd , / Y < / strong > < / p >

We build the container again using the docker build command:

<strong>docker build –t mycontainerizedwebsite .</strong> 1 < strong > docker build – t mycontainerizedwebsite . < / strong >

This now finally results in our web application in a container that we can then run on any windows server that has windows containers enabled.

Running the website in the container

In order to test if we succeeded we now issue the docker run command and then map the container port 80 to a port on our host. This can be done by using the –p option, where you specify a source and destination port. We also need to specify a command that ensures the container keeps running. For this we now use e.g. a command like ping –t which will result in an endless ping loop, that is enough to keep the container running. so to test the container we now run the following command:

docker run –p 80:80 mycontainerizedwebsite ping localhost -t 1 docker run – p 80 : 80 mycontainerizedwebsite ping localhost - t

Now we can browse to the website. Be aware that you can only reach the container from the outside, so if you would browse to localhost, which results in the 127.0.0.0 you will not see any results. You need to address your machine on its actual hostname or outside IP address.

Summary

To summarize what we have done, we first created a docker image capable of running IIS, then we added ASP.NET 4.5, then we added webdeploy and finally we deployed our website to the container using webdeploy and the package generated by Visual Studio.

In the next post I will show you how we can use this image in build and release management using VSTS and then deploy the container to a server so we can run automated tests as a stage in the delivery pipeline.