In my last post, I explained how to install Docker and how to run containers. Today, we will walk through creating a Docker container using a Dockerfile.

A Dockerfile (no file extension) is a definition file that will build and run a container. That container can be a simple Microsoft IIS web application or Python/Flask application or a simple build/reporting service. A definition file helps us with our operational tasks, especially when we are building services or scripts for the repeatable tasks we face on a daily basis.

Here is an example of a Dockerfile that will set up an IIS web server with ASP.NET 4.5 on a Windows system:

FROM microsoft/iis

RUN mkdir c:\myapp
RUN powershell -NoProfile -Command \
    Install-WindowsFeature NET-Framework-45-ASPNET; \
    Install-WindowsFeature Web-Asp-Net45; \
    Import-Module IISAdministration; \
    New-IISSite -Name "MyApp" -PhysicalPath C:\myapp -BindingInformation "*:8000:"


ADD bin/ /myapp

Wow, I bet you didn't think these few lines would set up an entire IIS web application with ASP.NET 4.5, did you? Well, they do! Let's break this down a bit further.

As explained in my previous post, Docker images are prebuilt "prerequisites" we can install and use when creating and running our container. Within a Dockerfile we specify the base image we want to use by declaring FROM {image name}. In this case, we are using the Docker Hub image for an IIS server Microsoft has provided.

FROM microsoft/iis

The second statement you see uses the RUN command to tell the container, once it is running, to call mkdir c:\myapp. At this point, it creates a new directory inside our container itself called c:\myapp.

At this point Docker has downloaded and built a containerized application based of the Microsoft/iis image with all the base prerequisites needed for setting up an IIS server. In addition we are telling the container also to create a new "virtual" folder inside the container itself. You don't really have access to this location, meaning you won't see it on your local file system. At this point, you just need to trust Docker is doing what you specified (and it is).

Moving on, the next statement you see is another RUN command:

RUN powershell -NoProfile -Command \
    Install-WindowsFeature NET-Framework-45-ASPNET; \
    Install-WindowsFeature Web-Asp-Net45; \
    Import-Module IISAdministration; \
    New-IISSite -Name "MyApp" -PhysicalPath C:\myapp -BindingInformation "*:8000:"

This RUN command is a bit different but does essentially the same thing. This time we are now specifying that we should create a new PowerShell "shell" by calling:

powershell -NoProfile -Command

Next, we specify our standard PowerShell commands as normal. You may notice that each line has a "\" at the end of it. The backslash is to ensure line continuation within the Docker container.

Install-WindowsFeature NET-Framework-45-ASPNET; \
Install-WindowsFeature Web-Asp-NET45; \
Import-Module IISAdministration; \
New-IISSite -Name "MyApp" -PhysicalPath C:\myapp -BindingInformation "*:8000:"

We then install the NET-Framework-45-ASPNET and Web-Asp-Net45 Windows features, just like we would do on a normal IIS web server. We then import the IISAdministration PowerShell module and create a new IIS website called MyApp. The New-IISSite cmdlet also allows us to specify a PhysicalPath and a specific port to bind to. In our case, we are binding all requests to port 8000.

Next, we then run the EXPOSE networking option in our Dockerfile. This option is a bit confusing to some, but it allows the individual who is generating the Docker container to specify a network port the individual can use to interact with the container. EXPOSE does not actually expose the network port. To expose a port to the world (or our network), you would need to specify another option when you run your container. For example, you would do the following:

docker run {image} -p 80

This would actually expose the container to a network outside your local system.

Within our folder that contains our Dockerfile, we should also have a folder named bin. Within this folder, we should have a basic HTML file called index.html with the following content:

         Hello from my Docker for Windows Container!
   <P>This is very minimal "hello world" HTML document, but it's running within Docker for Windows</P>

The last statement in our Dockerfile is the ADD command. This command will add files or scripts or whatever you have specified to the container.

ADD bin/ /myapp

How the ADD command works is that it takes the current directory holding your Dockerfile, and if you have specified a specific folder, like bin/, it would add this directory and all of its contents to /myapp within the Docker container. Here's a visual representation of this:

Add files from local file system to your Docker container

Add files from local file system to your Docker container

Now that we have our Dockerfile and our bin/index.html in the same folder, we will now build and run our new container!

To run our new container, open up your PowerShell console. Next, change directories to the folder container for your Dockerfile and bin/index.html folder. For me, I have these located at C:\Docker For Windows Example:

[Open PowerShell Console]
cd 'C:\Docker For Windows Example'
docker build .

Please note that the full command is docker build . The period at the end is needed, and it references the location of our Dockerfile.

After we have pulled down our image from Docker Hub, we should now have a new IIS website set up and running our index.html page. You can view it by going to your browser and going to:

Besides the options I mentioned in our example, you have additional commands available that I believe you will find extremely useful. These additional commands are:

ENTRYPOINT/CMD:     You may see this command as either ENTRYPOINT or CMD, but there are only minor differences between the two. An example of how to use CMD is as follows:

General Example: CMD ["executable","param1","param2"]
Python Example: CMD ["python", "/usr/src/app/"]
PowerShell Example: CMD [powershell.exe, -executionpolicy, bypass, c:\startup.ps1]

ENV: The ENV statement allows you to specify environmental variables within the container you are running. These can be great for a handful of variables, but this command does slow down your build process.

WORKDIR: WORKDIR allows you to set the working directory within a container. This is great if you want to use relative paths within your container. We'd typically use this before we call our RUN, CMD, ENTRYPOINT, etc. commands in our Dockerfile

You can find more information about all the commands available by visiting Docker's official documentation. Please view this documentation here.

Now that we understand the basics on building containers, we should be familiar enough to start playing around with all the available images on Docker Hub and even starting to create our own.

In the next segment of this series, we will go a bit further and talk about using docker-compose. This amazing feature will allow you to create multiple containers simultaneously. Why is this useful? Imagine creating an application that has both a front-end UI and a back-end database. In the meantime, please check out more information about Docker Compose here.

Articles in seriesDocker on Windows
  1. Install Docker and run containers on Windows
  2. Create a Docker container on Windows with a Dockerfile
1 Comment
  1. Danish Zahid 4 years ago

    Hey, great tutorial.

    Can you please provide some guidance on how to tweak the Dockerfile in order to run a shiny app.

    Thank you.

Leave a reply

Please enclose code in pre tags

Your email address will not be published.


© 4sysops 2006 - 2023


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account