Today we learn to leverage Azure (the Microsoft cloud), Windows PowerShell, and Docker to deploy Windows Server 2016–based virtual containers, all without either the Hyper-V hypervisor or Linux!
Latest posts by Timothy Warner (see all)

I’m going to teach you how to deploy Windows Server 2016 in a Docker virtual container from an Azure-hosted virtual machine (VM). To help you understand our goal, take a look at the following diagram and I’ll walk you through it:

Schematic diagram of our lab environment

Schematic diagram of our lab environment

First, we’ll deploy a new Azure VM running the latest Technical Preview (TP) build of Windows Server 2016. This particular OS image includes the Docker runtime environment that enables containers in the first place.

The great beauty of running Docker containers is that each application or service running inside a container is completely isolated from any other app/service running on the host. Therefore, instead of maintaining and patching multiple VMs, we patch one host and control our containers either individual or “as a herd.”

Preparing our environment

Open an elevated PowerShell ISE session on your computer and connect to your Azure subscription. Of course, you’ll first need to install the Azure PowerShell module. In the following example, I connect to my subscription named “150dollar” and Azure storage account named “150west”:

Select-AzureSubscription -SubscriptionName '150dollar'
Set-AzureSubscription -SubscriptionName '150dollar' -CurrentStorageAccountName 150west

The following code first retrieves the latest version of the Windows Server Container Preview operating system image. It then deploys a new small Azure VM named containerhost2 with user-specified administrator credentials and a connection to the Subnet-1 default virtual network address space:

$image = (Get-AzureVMImage | Where-Object {$_.label –like '*container*'}| Sort-Object –Property PublishedDate -Descending)[0].imagename

New-AzureVMConfig -Name 'containerhost2' -InstanceSize Small -ImageName $image | Set-AzureSubnet -SubnetNames 'Subnet-1' | Add-AzureProvisioningConfig -Windows -AdminUsername 'trainer' -Password 'M@1Pa$$w0rd!' | New-AzureVM -ServiceName 'west150service' -VNetName 'West150Network' -WaitForBoot

After the process completes, you can always run Get-AzureVM to check the VM run status:

ServiceName    Name           Status   
-----------    ----           ------   
west150service containerhost2 ReadyRole

Examining the environment

I had difficulty using the VM’s WSMan PowerShell remoting endpoint, so instead I cut my losses by logging in to the “classic” Azure management portal, navigating to Virtual Machines, selecting the containerhost2 VM, and clicking Connect to generate an .RDP file.

I hate to say it, but sometimes the GUI approach is faster

I hate to say it, but sometimes the GUI approach is faster than PowerShell.

What’s interesting is that, after you’re in the RDP session, all you get is a cmd.exe console prompt! I’m not exactly sure how Microsoft hacked this Windows Server 2016 build, but you can run sconfig so the environment feels and acts like Server Core. Technically, Microsoft calls this environment the Windows Server Container Host System.

Anyway, let’s poke around a bit, starting with verifying the Windows Server version:


Microsoft Windows [Version 10.0.10514]

Okay. Let’s switch to PowerShell and see if we can find Docker anywhere:

Windows PowerShell
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\Users\trainer> Get-Service -Name *docker*

Status   Name               DisplayName
------   ----               -----------
Running  Docker             Docker Daemon

Bingo! If you inspect the service list, you won’t find Hyper-V (remember that, under the hood, Azure VMs are themselves Hyper-V virtual machines).

Get-Command -Module Containers | Select-Object -Property Name | Sort-Object -Property Name | Format-Wide -Column 2

Add-ContainerNetworkAdapter                Connect-ContainerNetworkAdapter
Disconnect-ContainerNetworkAdapter         Export-ContainerImage
Get-Container                              Get-ContainerHost
Get-ContainerImage                         Get-ContainerNetworkAdapter
Import-ContainerImage                      Install-ContainerOSImage
Move-ContainerImageRepository              New-Container
New-ContainerImage                         Remove-Container
Remove-ContainerImage                      Remove-ContainerNetworkAdapter
Set-ContainerNetworkAdapter                Start-Container
Stop-Container                             Test-ContainerImage

Here’s a critical note: You can manage a container either by using Windows PowerShell or by using native Docker commands. Again, that’s a binary proposition: either/or. In this tutorial, we’ll use native Docker commands because they are already entrenched in the community.

Of course, Windows PowerShell allows us to run external commands, and Docker is no exception. Run the following command to get a full command list:

docker help

Deploying a Windows Server 2016 container

In Docker nomenclature, an image represents a container template. We can “sorta kinda” consider a Docker image in the same vein as a Windows Imaging Format (.wim) “golden image.”

We’ll start by listing available containers on our host (we can also run Get-ContainerImage):

PS C:\> docker images
windowsservercore  10.0.10514.0  0d53944cb84d  3 months ago  9.697 GB
windowsservercore  latest        0d53944cb84d  3 months ago  9.697 GB

Okay. So it looks like we have only Server Core available to us. No problem. We’ll use the run Docker verb to create a new container based on a given image. The -it switch puts us into an interactive terminal (console) session within the container after it’s online:

docker run -it --name corecontainer windowsservercore cmd

What happens next is a bit confusing because we’ve been in a console environment, and now you’ll find yourself in another console environment; namely, you’re in the Server Core container.

Start PowerShell and create a sample file in the root of drive C:. We’re doing this to prove that we’re working with a Windows Server 2016 container and not the host itself:

New-Item 'C:\container.txt' -Type File -Force -Value 'Hello from the container!'

Type exit twice to first close PowerShell and then leave the container and return to the host VM.

Now run dir *.txt and what do you see? Nothing, because the container.txt file exists in the Server Core container and not the host! This may be an underwhelming example, but I trust you get the idea.

Further actions

Let me introduce you to a few more Docker commands before we close today’s lesson. First of all, know that the --help switch gives you command-specific help. For example:

docker run --help

Somewhat confusingly, Docker uses ps to list all containers. You Linux admins know that we use an entirely different ps command to list processes,

I’ve modified the following output a bit to make it easier for you to read:

PS C:\> docker ps -a
CONTAINER ID    IMAGE         COMMAND  STATUS    NAMES               000d85474a02    windowsserve  "cmd"    Exited    corecontainer     b7d3f7833cae    windowsserve  "-cmd"   Created   dockerdemo

We stop and start containers using the appropriate verbs along with the container ID or container name:

docker stop b7d3f7833cae

docker start b7d3f7833cae

After a container is started, you can attach to it with, well, the attach verb:

docker attach b7d3f7833cae


Docker containers have many advantages over traditional hypervisor-based virtual machines, including but not limited to the following:

  • Containers are much smaller than VMs are and they consume fewer system resources.
  • Container density per physical host is greater than VM density is.
  • Containers support rapid application deployment.
  • Containers have a reduced attack surface compared to that of VMs.
  • Container management is easier than VM management is.
  • Containers are more portable (especially across OS kernels) than VMs are.

The Microsoft-Docker partnership bears beautiful cross-platform fruit. You must remember that Docker was created for us in the Linux/UNIX world. The fact that Windows Server 2016 supports the Docker runtime environment natively is nothing short of phenomenal.


Leave a reply

Your email address will not be published. Required fields are marked *


© 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