Dockerfile on Windows

The Docker engine includes tools for automating the creation of container images. While container images can be created manually using the docker commit command, adopting an automated image creation process provides many benefits including:

  • Storing container images as code.
  • Rapid and precise recreation of container images for maintenance and upgrade purposes.
  • Continuous integration between container images and the development cycle.

The Docker components that drive this automation are the Dockerfile, and the docker build command.

  • Dockerfile – a text file containing the instructions needed to create a new container image. These instructions include identification of an existing image to be used as a base, commands to be run during the image creation process, and a command that will run when new instances of the container image are deployed.
  • Docker build - the Docker engine command that consumes a Dockerfile, and triggers the image creation process.

This document will introduce using a Dockerfile with Windows containers, discuss syntax, and detail commonly used Dockerfile instructions.

Throughout this document, the concept of container images and container image layers will be discussed. For more information on images and image layering see the quick start guide to images.

For a complete look at Dockerfiles, see the Dockerfile reference at docker.com.

Dockerfile Introduction

Basic Syntax

In its most basic form, a Dockerfile can be very simple. The following example creates a new image, which includes IIS, and a ‘hello world’ site. This example includes comments (indicated with a #), that explain each step. Subsequent sections of this article will go into more detail on Dockerfile syntax rules, and Dockerfile instructions.

Please note that Dockerfile must be created with no extension. In Windows to do so simply create the file with your editor of choice than save it using the notation "Dockerfile" including the quotes.

# Sample Dockerfile

# Indicates that the windowsservercore image will be used as the base image.
FROM microsoft/windowsservercore

# Metadata indicating an image maintainer.
MAINTAINER jshelton@contoso.com

# Uses dism.exe to install the IIS role.
RUN dism.exe /online /enable-feature /all /featurename:iis-webserver /NoRestart

# Creates an HTML file and adds content to this file.
RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html

# Sets a command or process that will run each time a container is run from the new image.
CMD [ "cmd" ]

For additional examples of Dockerfiles for Windows, see the Dockerfile for Windows Repository.

Instructions

Dockerfile instructions provide the Docker Engine with the steps needed to create a container image. These instructions are performed in order, and one-by-one. Here are the details for some basic Dockerfile instructions. For a complete list of Dockerfile instructions, see Dockerfile Reference on Docker.com.

FROM

The FROM instruction sets the container image that will be used during the new image creation process. For instance, when using the instruction FROM microsoft/windowsservercore, the resulting image is derived from, and has a dependency on, the Windows Server Core base OS image. If the specified image is not present on the system where the Docker build process is being run, the Docker engine will attempt to download the image from a public or private image registry.

Format

The FROM instruction takes a format of:

FROM <image>

Example

FROM microsoft/windowsservercore

For detailed information on the FROM instruction, see the FROM Reference on Docker.com.

RUN

The RUN instruction specifies commands to be run, and captured into the new container image. These commands can include items such as installing software, creating files and directories, and creating environment configuration.

Format

The RUN instruction takes a format of:

# exec form

RUN ["<executable", "<param 1>", "<param 2>"]

# shell form

RUN <command>

The difference between the exec and shell form, is in how the RUN instruction is executed. When using the exec form, the specified program is run explicitly.

The following example used the exec form.

FROM microsoft/windowsservercore

RUN ["powershell", "New-Item", "c:/test"]

Examining the resulting image, the command that was run is powershell New-Item c:/test.

docker history doc-exe-method

IMAGE               CREATED             CREATED BY                    SIZE                COMMENT
b3452b13e472        2 minutes ago       powershell New-Item c:/test   30.76 MB

To contrast, the following example runs the same operation, however using the shell form.

FROM microsoft/windowsservercore

RUN powershell New-Item c:\test

Which results in a run instruction of cmd /S /C powershell New-Item c:\test.

docker history doc-shell-method

IMAGE               CREATED             CREATED BY                              SIZE                COMMENT
062a543374fc        19 seconds ago      cmd /S /C powershell New-Item c:\test   30.76 MB

Windows Considerations

On Windows, when using the RUN instruction with the exec format, backslashes must be escaped.

RUN ["powershell", "New-Item", "c:\\test"]

When the target program is a Windows Installer, an extra step is required before launching the actual (silent) installation procedure: extraction of the setup, via the /x:<directory> flag. Besides this, the command needs to be waited for exit. Otherwise, the process will end prematurely, without installing anything. For details, please consult the example below.

Examples

This example uses DISM to install IIS in the container image.

RUN dism.exe /online /enable-feature /all /featurename:iis-webserver /NoRestart

This example installs the Visual Studio redistributable package. Note here that Start-Process and the -Wait parameter are used to run the installer. This will ensure that the installation completed before moving onto the next step in the Dockerfile.

RUN powershell.exe -Command Start-Process c:\vcredist_x86.exe -ArgumentList '/quiet' -Wait

For detailed information on the RUN instruction, see the RUN Reference on Docker.com.

COPY

The COPY instruction copies files and directories to the filesystem of the container. The files and directories need to be in a path relative to the Dockerfile.

Format

The COPY instruction takes a format of:

COPY <source> <destination>

If either source or destination include whitespace, enclose the path in square brackets and double quotes.

COPY ["<source>", "<destination>"]

Windows Considerations

On Windows, the destination format must use forward slashes. For example, these are valid COPY instructions.

COPY test1.txt /temp/
COPY test1.txt c:/temp/

However, the following will not work.

COPY test1.txt c:\temp\

Examples

This example adds the contents of the source directory, to a directory named sqllite in the container image.

COPY source /sqlite/

This example will add all files that begin with config, to the c:\temp directory of the container image.

COPY config* c:/temp/

For detailed information on the COPY instruction, see the COPY Reference on Docker.com.

ADD

The ADD instruction is very much like the COPY instruction; however, it includes additional capabilities. In addition to copying files from the host into the container image, the ADD instruction can also copy files from a remote location with a URL specification.

Format

The ADD instruction takes a format of:

ADD <source> <destination>

If either source or destination include whitespace, enclose the path in square brackets and double quotes.

ADD ["<source>", "<destination>"]

Windows Considerations

On Windows, the destination format must use forward slashes. For example, these are valid ADD instructions.

ADD test1.txt /temp/
ADD test1.txt c:/temp/

However, the following will not work.

ADD test1.txt c:\temp\

Additionally, on Linux the ADD instruction will expand compressed packages on copy. This functionality is not available in Windows.

Examples

This example adds the contents of the source directory, to a directory named sqllite in the container image.

ADD source /sqlite/

This example will add all files that begin with config, to the c:\temp directory of the container image.

ADD config* c:/temp/

This example will download Python for Windows into the c:\temp directory of the container image.

ADD https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe /temp/python-3.5.1.exe

For detailed information on the ADD instruction, see the ADD Reference on Docker.com.

WORKDIR

The WORKDIR instruction sets a working directory for other Dockerfile instructions, such as RUN, CMD, and also the working directory for running instances of the container image.

Format

The WORKDIR instruction takes a format of:

WORKDIR <path to working directory>

Windows Considerations

On Windows, if the working directory includes a backslash, it must be escaped.

WORKDIR c:\\windows

Examples

WORKDIR c:\\Apache24\\bin

For detailed information on the WORKDIR instruction, see the WORKDIR Reference on Docker.com.

CMD

The CMD instruction sets the default command to be run when deploying an instance of the container image. For instance, if the container will be hosting an NGINX web server, the CMD might include instructions to start the web server, such as nginx.exe. If multiple CMD instructions are specified in a Dockerfile, only the last is evaluated.

Format

The CMD instruction takes a format of:

# exec form

CMD ["<executable", "<param>"]

# shell form

CMD <command>

Windows Considerations

On Windows, file paths specified in the CMD instruction must use forward slashes or have escaped backslashes \\. For example, these are valid CMD instructions.

# exec form

CMD ["c:\\Apache24\\bin\\httpd.exe", "-w"]

# shell form

CMD c:\\Apache24\\bin\\httpd.exe -w

However, the following will not work.

CMD c:\Apache24\bin\httpd.exe -w

For detailed information on the CMD instruction, see the CMD Reference on Docker.com.

Escape Character

In many cases a Dockerfile instruction will need to span multiple lines; this is done with an escape character. The default Dockerfile escape character is a backslash \. Because the backslash is also a file path separator in Windows, it can be problematic. To change the default escape character, a parser directive can be used. For more information on Parser directives, see Parser Directives on Docker.com.

The following example shows a single RUN instruction that spans multiple lines using the default escape character.

FROM microsoft/windowsservercore

RUN powershell.exe -Command \
    $ErrorActionPreference = 'Stop'; \
    wget https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \
    Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
    Remove-Item c:\python-3.5.1.exe -Force

To modify the escape character, place an escape parser directive on the very first line of the Dockerfile. This can be seen in the below example.

Note, only two values can be used as escape characters, the \ and the ` .

# escape=`

FROM microsoft/windowsservercore

RUN powershell.exe -Command `
    $ErrorActionPreference = 'Stop'; `
    wget https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; `
    Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; `
    Remove-Item c:\python-3.5.1.exe -Force

For more information on the escape parser directive, see Escape Parser Directive on Docker.com.

PowerShell in Dockerfile

PowerShell Commands

PowerShell commands can be run in a Dockerfile using the RUN operation.

FROM microsoft/windowsservercore

RUN powershell -command Expand-Archive -Path c:\apache.zip -DestinationPath c:\

REST Calls

PowerShell, and the Invoke-WebRequest command, can be useful when gathering information or files from a web service. For instance, if building an image that includes Python, the following example could be used. Consider setting $ProgressPreference to SilentlyContinue to achieve faster downloads.

FROM microsoft/windowsservercore

RUN powershell.exe -Command \
  $ErrorActionPreference = 'Stop'; \
  $ProgressPreference = 'SilentlyContinue'; \
  Invoke-WebRequest https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \
  Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
  Remove-Item c:\python-3.5.1.exe -Force

Invoke-WebRequest also works in Nano Server

Another option for using PowerShell to download files during the image creation process is to use the .NET WebClient library. This can increase download performance. The following example downloads the Python software, using the WebClient library.

FROM microsoft/windowsservercore

RUN powershell.exe -Command \
  $ErrorActionPreference = 'Stop'; \
  (New-Object System.Net.WebClient).DownloadFile('https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe','c:\python-3.5.1.exe') ; \
  Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
  Remove-Item c:\python-3.5.1.exe -Force

WebClient is not currently supported in Nano Server

PowerShell Scripts

In some cases, it may be helpful to copy a script into the containers being used during the image creation process, and then run from within the container. Note - this will limit any image layer caching, and decrease readability of the Dockerfile.

This example copies a script from the build machine into the container using the ADD instruction. This script is then run using the RUN instruction.

FROM microsoft/windowsservercore
ADD script.ps1 /windows/temp/script.ps1
RUN powershell.exe -executionpolicy bypass c:\windows\temp\script.ps1

Docker Build

Once a Dockerfile has been created and saved to disk, docker build can be run to create the new image. The docker build command takes several optional parameters and a path to the Dockerfile. For complete documentation on Docker Build, including a list of all build options, see build Reference on Docker.com.

Docker build [OPTIONS] PATH

For example, the following command will create an image named ‘iis’.

docker build -t iis .

When the build process has been initiated, the output will indicate status, and return any thrown errors.

C:\> docker build -t iis .

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM micrsoft/windowsservercore
 ---> 6801d964fda5

Step 2 : RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
 ---> Running in ae8759fb47db

Deployment Image Servicing and Management tool
Version: 10.0.10586.0

Image Version: 10.0.10586.0

Enabling feature(s)
The operation completed successfully.

 ---> 4cd675d35444
Removing intermediate container ae8759fb47db

Step 3 : RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
 ---> Running in 9a26b8bcaa3a
 ---> e2aafdfbe392
Removing intermediate container 9a26b8bcaa3a

Successfully built e2aafdfbe392

The result is a new container image, in this example named 'iis'.

docker images

REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
iis                 latest              e2aafdfbe392        About a minute ago   207.8 MB
windowsservercore   latest              6801d964fda5        4 months ago         0 B

Further Reading & References

Optimize Dockerfiles and Docker build for Windows

Dockerfile Reference on Docker.com