Tag Archives: Containerization

Composing your own Windows Container with a Dockerfile

In the previous blog post Getting Started with Windows Containers I showed how to run containers and pull existing containers from the public repository Docker Hub. Now it is time to create a new image and add it to Docker Hub.

I wanted to create a Hello World image that works on Windows Containers. I chose to create the Hello-World program using .NET Core – it runs cross platform (Linux, Mac & Windows), but I’m using Windows.

On the Windows Server 2016 container host I created in the previous blog post, I needed to install .NET Core. You can either go to http://dot.net/core to download or execute the following PowerShell to download the installer.

Invoke-WebRequest https://go.microsoft.com/fwlink/?LinkID=809122 -OutFile c:\dotnetinstall.exe

I created a folder called HelloWorld and executed the following commands in a command prompt:

PS C:\Users\aly\Desktop\HelloWorld> dotnet new
Created new C# project in C:\Users\aly\Desktop\HelloWorld.
PS C:\Users\aly\Desktop\HelloWorld> dotnet restore
log : Restoring packages for C:\Users\aly\Desktop\HelloWorld\project.json...
log : Writing lock file to disk. Path: C:\Users\aly\Desktop\HelloWorld\project.lock.json
log : C:\Users\aly\Desktop\HelloWorld\project.json
log : Restore completed in 1049ms.
PS C:\Users\aly\Desktop\HelloWorld> dotnet run
Project HelloWorld (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling HelloWorld for .NETCoreApp,Version=v1.0

Compilation succeeded.
0 Warning(s)
0 Error(s)

Time elapsed 00:00:01.8161040

Hello World!
PS C:\Users\aly\Desktop\HelloWorld> dotnet publish
Publishing HelloWorld for .NETCoreApp,Version=v1.0
Project HelloWorld (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
publish: Published to C:\Users\aly\Desktop\HelloWorld\bin\Debug\netcoreapp1.0\publish
Published 1/1 projects successfully
PS C:\Users\aly\Desktop\HelloWorld>

You can use any executable, I just needed something simple to work with. .NET Core is my simple choice.
I am going to base my image on the microsoft/windowsservercore image. But instead of installing .NET Core myself, I can use an image that already has .NET Core installed called microsoft/dotnet:windowsservercore. See all the official Microsoft Docker images at the Microsoft Docker Hub repository. So pull down the microsoft/dotnet:windowsservercore image

docker pull microsoft/dotnet:windowsservercore

If you want to play with it run the following command to start a container and a command prompt will appear. Type exit when you want to go back to the container host.

docker run -it microsoft/dotnet:windowsservercore

Now let’s create the Hello World image. Create a file called Dockerfile without extension outside the /HelloWorld folder and add this:

FROM microsoft/dotnet:windowsservercore
MAINTAINER Anders Lybecker (@Lybecker)
ADD /helloworld/bin/Debug/netcoreapp1.0/publish/ c:\\code
ENTRYPOINT dotnet c:\\code\\helloworld.dll

Line 1 dictates that I’m basing the Hello World image on the official image microsoft/dotnet:windowsservercore
Line 2 is just maintainer information and is optional
Line 3 adds the content of the publish folder of the container host to the image in c:\code
Line 4 sets the default command to execute the Hello World program

For more details see the Dockerfile reference.

Build the container by executing the docker build command. The image is named myhelloword and tagged with v1 for version 1. The last . specifies where the Dockerfile is located.

PS C:\Users\aly\Desktop> docker build -t myhelloworld:v1 .
Sending build context to Docker daemon 341.5 kB
Step 1 : FROM microsoft/dotnet:windowsservercore
---> 1e21a0790e96
Step 2 : MAINTAINER Anders Lybecker (@Lybecker)
---> Running in 6812a0ecf67d
---> 5dce994e32a4
Removing intermediate container 6812a0ecf67d
Step 3 : ADD /helloworld/bin/Debug/netcoreapp1.0/publish/ c:\\code
---> 22fade758f23
Removing intermediate container 665f9e677611
Step 4 : ENTRYPOINT dotnet c:\\code\\helloworld.dll
---> Running in dad461888c4c
---> 204ed6ed0b59
Removing intermediate container dad461888c4c
Successfully built 204ed6ed0b59

That’s it. You have now created your own image. Let’s try to run it

PS C:\Users\aly\Desktop> docker run myhelloworld:v1
Hello World!

You can see the image in the local image repository with the docker images command.

PS C:\Users\aly\Desktop> docker images
REPOSITORY                  TAG               IMAGE ID     CREATED        SIZE
myhelloworld                v1                204ed6ed0b59 10 minutes ago 8.111 GB
microsoft/dotnet            windowsservercore 1e21a0790e96 2 weeks ago    8.111 GB
microsoft/windowsservercore 10.0.14300.1030   02cb7f65d61b 10 weeks ago   7.764 GB
microsoft/windowsservercore latest            02cb7f65d61b 10 weeks ago   7.764 GB

The myhelloworld:v1 image is based on the microsoft/dotnet:windowsservercore which is based om microsoft/windowsservercore:10.0.14300.1030. You can see all the layers via the docker history command

PS C:\Users\aly\Desktop> docker history myhelloworld:v1
204ed6ed0b59 12 minutes ago cmd /S /C #(nop) ENTRYPOINT ["cmd" "/S" "/C" 46.58 kB
22fade758f23 12 minutes ago cmd /S /C #(nop) ADD dir:4bef0fa9bcfacdaa9bb8 40.96 kB
5dce994e32a4 12 minutes ago cmd /S /C #(nop) MAINTAINER Anders Lybecker 181.2 MB
1e21a0790e96 2 weeks ago cmd /S /C mkdir warmup && cd warmup & 40.96 kB
2 weeks ago cmd /S /C #(nop) ENV NUGET_XMLDOC_MODE=skip 4.756 MB
2 weeks ago cmd /S /C setx /M PATH "%PATH%;%ProgramFiles% 160.7 MB
2 weeks ago cmd /S /C powershell -NoProfile -Command 40.96 kB
2 weeks ago cmd /S /C #(nop) ENV DOTNET_SDK_DOWNLOAD_URL 40.96 kB
2 weeks ago cmd /S /C #(nop) ENV DOTNET_SDK_VERSION=1.0. 7.764 GB

I have made my Hello World image available on Docker Hub, so you can pull and run the image on your Windows Container host like so:

PS C:\Users\aly\Desktop> docker pull anderslybecker/dotnet-hello-world:windowsservercore
windowsservercore: Pulling from anderslybecker/dotnet-hello-world
Digest: sha256:1df17a8a38d969b71b38333be25f76757e69f1537c7a86a6ee966bca87163464
Status: Image is up to date for anderslybecker/dotnet-hello-world:windowsservercore
PS C:\Users\aly\Desktop> docker run anderslybecker/dotnet-hello-world:windowsservercore
Hello World!

Getting started with Windows Containers

Soon Windows Server 2016 will be released and so will the Docker Engine compatible Windows Containers feature. Here is a tutorial for you to get started with Windows Containers.

One thing to be aware of when working with containers is that the underlying host must be of the same type of operating system as the container running on the host. Linux containers on Linux hosts and Windows containers on Windows hosts.

First a container host is needed – you can use Windows 10 Anniversary Update or a Windows Server 2016.

The easiest way of getting started is to spin up a Windows Server 2016 on Azure (get a free trial) with the Container feature enabled.

  1. Select new
  2. Type “container” to filter only for container images
  3. Select the “Windows Server 2016 with Containers” equivalent (as of writing Tech Preview 5)CreateWindowsServer2016Container
  4. Follow the wizard to specify VM size etc.

Alternatively, you can follow Windows Containers on Windows Server guide to install the Container feature on an existing Windows Server 2016.

Once you have created the host you can connect to the host via RDP (in the Azure portal use the ”Connect” button in the top menu).

Start up a command prompt or the PowerShell. You can use PowerShell for Docker or the Docker CLI to execute Docker commands. The commands are the same across platform – no matter if you are using Linux or Windows-based containers. I’ll be using the Docker CLI commands. The common commands are:

  • Docker info – which will show you version etc.
  • Docker images – shows all the images in the local repository
  • Docker ps – show all the running containers
  • Docker ps -a – the -a (or -all) shows all containers including containers that are no longer running
  • Docker run – run an instance of an image

Let’s get started.

Run the following command to see which images are available in the local repository.

PS C:\Users\aly\Desktop> docker images
REPOSITORY                  TAG             IMAGE ID     CREATED      SIZE
microsoft/windowsservercore 10.0.14300.1030 02cb7f65d61b 10 weeks ago 7.764 GB
microsoft/windowsservercore latest          02cb7f65d61b 10 weeks ago 7.764 GB
PS C:\Users\aly\Desktop>

On my Windows Server 2016 Tech Preview 5 there are two images both with the name microsoft/windowsservercore with two different tags. Both of them has the same image id, so they are the same image with two different tags.

To start a container of the image tagged with ‘latest’ run the following:

PS C:\Users\aly\Desktop> docker run microsoft/windowsservercore:latest
Microsoft Windows [Version 10.0.14300]
(c) 2016 Microsoft Corporation. All rights reserved.

PS C:\Users\aly\Desktop>

The tag is optional, but the default value is ‘latest’.

The container was started and a command prompt appeared, but then it shut down again and it returned to my PowerShell prompt.

If you want to interact with the container, add the -it (interactive) option. You also have the option of specifying which process should be run in the container (cmd is default for this image):

docker run -it microsoft/windowsservercore:latest cmd

Now a command prompt appears and you are in the context of the container. If you modify a file e.g. adds or deletes a file, then the changes will only apply to the container and not the host.

Create a simple file like this:

echo "Hello Windows Containers" > hello.txt

You can exit the container by typing exit, and the container will terminate. Alternatively, you can press CTRL + P + Q to exit and leave the container running.
If you left the container running, you can see the container by listing the Docker processes:

PS C:\Users\aly\Desktop> docker ps
CONTAINER ID IMAGE                             COMMAND   CREATED       STATUS    PORTS NAMES
23ca16bb6fdb microsoft/windowsservercore:latest "cmd" 4 minutes ago Up 4 minutes pedantic_lamport

If the container was terminated, the -a option needs to be appended.
You can reattach to the container by specifying the container id or name. In my case 23ca16bb6fdb or pedantic_lamport like so:

Docker attach 23ca16bb6fdb

You only have the Windows Server Core image in the local repository, but you can download others by pulling from Docker Hub.

docker pull microsoft/nanoserver

Remember that only Windows-based images will run on a Windows host, so if you try the Hello-World Linux-based image, it will fail with a not so elaborate error message.

PS C:\Users\aly\Desktop> docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
c04b14da8d14: Extracting [==================================================>] 974 B/974 B
failed to register layer: re-exec error: exit status 1: output: ProcessBaseLayer C:\ProgramData\docker\winc266a137b0b1fffedf91d8cd6fcb6560f12afe5277e44bca8cb34ec530286: The system cannot find the path specified.

For now it is not easy to differentiate between Linux or Windows-based images on Docker Hub. I would have wished for a filter, making it easier to find relevant images.

Microsoft has a public repository of all the official released Microsoft container images.