Windows Docker Containers
Introduction
In this post I am going to show step by step how to install a local version of Windows Server 2016 TP5 in Hyper-V and how to configure it to be a container host.
Tutorial
It is still not straight forward to configure a Windows Server 2016 as a container host and use Docker to build and run containers. Microsoft provides pre-configured VMs in Azure but I want to run a Windows Container host on my developer machine in Hyper-V. Up to TP4 I failed to do this. Now that TP5 is finally out I tried again and after some first failures I finally succeeded. I want to describe the steps necessary to achieve this on my machine and I hope that I can help some folks out there trying the same to avoid all the hassle I went through.
Enable Hyper-V
First we need to enable Hyper-V on our laptop. Do this via Control Panel. In the Programs section select Turn Windows features on or off.
Download Windows Server 2016 TP5
Once the feature is installed we have to reboot our machine. Next we want to download Windows Server 2016 TP5. We can get it from here. Make sure you download Windows Server 2016 Technical Preview 5 and not the Hyper-V or the Essentials version.
Define a switch
Now we can start the Hyper-V management console. First we add a new virtual switch. Make sure that you select the type External and that you link it to you Ethernet card. Note that there is an error that makes it impossible to link it to a WLAN port. I lost quite some time trying to configure my switch when I was on WLAN and not on a wired connection.
Create the VM
Once we have defined the external switch we can create a new VM. Navigate through the VM creation wizard and create a new VM. When asked, mount the ISO that you just downloaded to the VM. Once you’re done, start the VM. First we are asked to define a new password for the Admin. Then we can start working. Make sure that you have internet connection using e.g. ping
or ipconfig
.
Make it a container host
Now we are ready to make this Windows Server 2016 TP5 VM a container host. For this we use Powershell
. On the command prompt enter powershell
. Next we load a script prepared by Microsoft from http://aka.ms
. We use the wget
command for this. Please note the URL that we’re using. It is different from what is published in many documents and videos of Microsoft.
wget http://aka.ms/tp5/install-ContainerHost -OutFile c:\install-ContainerHost.ps1
Now we can use this Powershell file to configure our server as a container host by executing this command
powershell -NoProfile -ExecutionPolicy Bypass c:\install-ContainerHost.ps1
Now we need to be patient, very patient. You might wanna brew some coffee and watch a nice movie while the script is running. It took more than an hour on my decently fast machine having an SSD as the main drive. A lot of things are going to happen. The server is also going to reboot some time into the operation. After the reboot the script will download the WindowsServerCore container image and extract it. Your screen should look similar to this
When the script execution has finally come to an end we **need* to restart the server otherwise Docker won’t see the new image when executing docker images
. When I executed the said command without first restarting the Docker Daemon I nearly got a heart attack since no image was listed. Another waste of time I thought, but then I did what I always do when nothing works anymore… We can do this like this net stop "Docker Daemon"<br />
net start "Docker Daemon"
Now using the docker images
command I got this
Hallelujah, I thought! There is is, the expected windowsservercore image. It is currently the only image available to us on our machine.
Tagging an image
To tag our image we can use the normal Docker tag command
docker tag [image-id] windowsservercore:latest
where [image-id]
is the ID of the Docker image as listed in the previous picture. In my case this is dfee88ee9fd
.
More images
We can use the Powershell command Find-ContainerImage
to see what other images are available to us. We should see this
Apparently there is an image called NanoServer
available to us. Lets install it on our machine using this command
Install-ContainerImage -Name NanoServer
This will take a few moments and once done we can verify that we now have not only windowsservercore
but also nanoserver
listed as available images on the local machine. Use this command
Get-ContainerImage
and the result should be similar to this
After restarting the Docker daemon (see above) we can also see the nanoserver
image using the docker images
command
Create Container Images
IIS Image
We can take it as our base and create some new images of from it. Let’s create an IIS image first as a test. Let’s run an instance of the image windowsservercore
as follows
docker run -it windowsservercore powershell
Once we’re inside the container running in a Powershell console we use this command to install IIS
Install-WindowsFeature web-server
and we can exit the container by typing exit
in the console. Finally we create an image from the current state of the container using this command
docker commit iisbase windowsservercore-iis
This operation takes a moment. Once we’re done we can use docker images
to verify that we have indeed created a new image called windowsservercore-iis
. We can run a Docker container from this image and open port 80 to the public by using this command
docker run -dt --name iisdemo -p 80:80 windowsservercore-iis
If we open a browser and navigate to the IP address of our container host VM (in my case this is 192.168.1.95) we see the expected result
Great, we have our first custom built container running! But wait a second… Docker does not recommend to build images using the docker commit
command. The preferred way is to use a Dockerfile
.
Using a Dockerfile to create an image
Let’s do this. Create a folder c:\docker\iis
and navigate to this folder. Create a new file using
echo "" > Dockerfile
then use notepad to edit this file
notepad .\Dockerfile
Now add the following content to the file
FROM windowsservercore<br />
RUN ["powershell","Install-WindowsFeature","web-server"]
Save the file. Make sure that you save the file as ASCII encoded or UTF-8 without encoding. Docker doesn’t like the BOM at the beginning of a standard UTF-8 encoded file. We should see an output similar to the following
And once again we can run an instance of this image with
docker run -dt --name iisdemo -p 80:80 iis
Navigating with the browser to the IP address of the VM shows the same result as above. The default IIS site is shown as expected.
Nginx Image
Now let’s create an nginx image as a second test. Let’s again run an instance of the image windowsservercore
as follows
docker run -it windowsservercore powershell
Now after a short time we should find ourselves inside a Docker container in a Powershell console. Now we want to download nginx and can do this as follows
wget http://nginx.org/download/nginx-1.10.0.zip -UseBasicParsing -OutFile nginx.zip
This will take a few seconds to download. Now we need to extract this zip file using the following command
Expand-Archive nginx.zip
This will expand the file into a folder nginx
. The binaries are in a subfolder nginx-1.10.0
. We can now exit this container by typing exit
in the Powershell console. Now we can use this container to create an image from it. First we need to know what it’s id is. Let’s do this by using docker ps -a
. Our container should be in the list and it’s status should be Exited
. Remember the ID of the container. Now we can use the following command to generate an image
docker commit [container-id] windowsservercore-nginx
When we now use docker images
to get a list of container images we should see this
As mentioned above, a better way to create an Nginx based image is to use a Dockerfile
. For this let’s create a folder c:\docker\nginx
. In this folder we create a new new file called Dockerfile
. The content of the file should be
We can build this image using
docker build -t nginx .
and then we run a container like this
docker run -dt --name nginx -p 80:80 nginx
if we navigate with a browser to our IP address we see this
Nice. We just have successfully build a second custom image based on the popular Nginx web server.
Summary
In this post I have described how we can configure a developer machine to run a Windows Server 2016 TP5 VM in Hyper-V which is configured to be a Windows Container host. I also have shown how we can now use Docker to build container images and run instances of those as containers. It is very nice to see that the Docker API for Windows Containers is exactly the same as for Linux Containers. This makes life much easier for us developers that have to deal with both operating systems on a daily basis. If on the other hand you’re a pure Windows developer you can also use Powershell to create container images and instantiate and run containers.