Blog

Windows Containers: Build

This post is a building block for working with containers on Windows. I have covered elsewhere installing the Containers feature with Docker, and running containers with the Docker command line. We can’t do much that is useful without building our own images. Doing this tells us a lot about what we can and cannot do with containers on Windows.

Some preamble:

  1. A container is not persistent. It is an instance of an image. You can make changes inside a running container, for example installing or configuring an application, but unless you build a new container image with your changes, they will not be saved.
  2. A Windows container has no GUI. Any installation or configuration will be done at the command line.
  3. Therefore we should make our changes in a script, containing the instructions to build a new image.
  4. This script is a Dockerfile.

The command to build an image is: docker image build with a range of options, including the path to the Dockerfile.

You can also run: docker image commit to create a new image from a running container. This gives scope for configuring a container interactively before saving it as a new image. But, since the only interface to configure the container is the command line, and since the same commands can be performed in the Dockerfile, this has limited use.

Building an image in Docker is a similar idea to building an image for OS deployment. The Dockerfile is like the task sequence in MDT or SCCM, being a scripted set of tasks. The documentation is here: Dockerfile reference. An example is this one, from Microsoft, for IIS on Windows Server Core:

FROM microsoft/windowsservercore
RUN powershell -Command Add-WindowsFeature Web-Server
ADD ServiceMonitor.exe /ServiceMonitor.exe
EXPOSE 80 
ENTRYPOINT ["C:\ServiceMonitor.exe", "w3svc"]

The basic structure of a Dockerfile is:

  • FROM to specify the image that the new image is developed from
  • ADD or COPY from source to destination to put new files into the image
  • RUN to execute commands to configure the image
  • CMD to specify a command to start the container with, if no other command is specified
  • EXPOSE to indicate what port or ports the application listens on
  • ENTRYPOINT to specify the services or executables that should run automatically when a container is created.

We can immediately see some implications:

  1. We don’t have to build every part of the end image in one Dockerfile. We can chain images together. For example, we could build a generic web server FROM microsoft/iis, then build specific web sites with other components in new images based on that.
  2. Adding a single feature is easy, like: Add-WindowsFeature Web-Server. But configuring it with all the required options will be considerably more complicated: add website; application pool; server certificate etc.
  3. We may want to bundle sets of commands into separate scripts and run those instead of the individual commands.
  4. There is no RDP to the container, no remote management, no access to Event Logs: and arguably we don’t need to manage the container in the same way. But we can add agents to the image, for example a Splunk agent.
  5. Static data can be included in the image, of course, but if we want dynamic data then we need to decide which folders it will be in, so we can mount external folders to these when we run the container.

It is rather like doing a scripted OS deployment without MDT. I would not be surprised if a GUI tool emerges soon to automate the build scripting.

You may find a number of Dockerfiles for Windows using the Deployment Image Servicing and Management (DISM) tool. There is a confusing choice of tools and no particular need to use DISM (or reason not to). DISM is typically used for offline servicing of Windows Imaging Format (WIM) images. For example it can be used to stream updates and packages into a WIM image by mounting it. But in the case of Docker images the changes are made by instantiating a temporary container for each RUN, and the DISM commands are executed online. This means we can use three different types of command to do the same thing:

  • Install-WindowsFeature from the ServerManager module in PowerShell
  • Enable-WindowsOptionalFeature from the DISM module in PowerShell
  • dism.exe /online /enable-feature from DISM.

Just to make life interesting and keep us busy, the commands to add a feature use different names for the same feature!

Windows Containers: Portainer GUI

When you first set up Containers on Windows Server 2016, you would imagine there would be some kind of management console. But there is none. You have to work entirely from the command line. Portainer provides a management GUI that makes it easier to visualise what is going on.

The Windows Container feature itself only provides the base Host Compute and Host Network Services, as Hyper-V extensions. There is no management console for these. Even if you install the Hyper-V role, as well as the Containers feature, you can’t manage images and containers from the Hyper-V management console.

Images and containers are created and managed by a third party application, Docker. Docker also has no management console. It is managed from the Docker CLI, either in PowerShell or the Command Prompt.

There is a good reason for this. But, for me at least, it makes it hard to visualise what is going on. Portainer is a simple management UI for Docker. It is open source, and itself runs as a container. It works by connecting to the Docker engine on the host server, then providing a web interface to manage Docker.

Portainer Dashboard

Portainer Dashboard

Setting up the Portainer container will also give us a better idea of how to work with Docker. Docker has a daunting amount of documentation for the command line, and it is not easy to get to grips with it.

Configure Docker TCP Socket

The first step in setting up Portainer is to enable the Docker service to listen on a TCP socket. By default Docker only allows a named pipe connection between client and service.

Quick version:

  • create a file with notepad in C:\ProgramData\docker\config
  • name the file daemon.json
  • add this to the file:
    {"hosts": ["tcp://0.0.0.0:2375","npipe://"]}
  • restart the Docker service.

The long version is: the Docker service can be configured in two different ways:

  1. By supplying parameters to the service executable
  2. By creating a configuration file, daemon.json, in C:\ProgramData\docker\config.

The parameters for configuring the Docker service executable are here: Daemon CLI Reference. To start Docker with a listening TCP socket on port 2375, use the parameter

-H tcp://0.0.0.0:2375

This needs to be configured either directly in the registry, at HKLM\SYSTEM\CurrentControlSet\Services\Docker; or with the Service Control command line:

sc config Docker binPath= ""C:\Program Files\docker\dockerd.exe\" --run-service -H tcp://0.0.0.0:2375"

The syntax is made difficult by the spaces, which require quotation with escape characters.

The easier way is to configure the Docker service with a configuration file read at startup, daemon.json. The file does not exist by default. You need to create a new text file and save it in the default location C:\ProgramData\docker\config. The daemon.json file only needs to contain the parameters you are explicitly configuring. To configure a TCP socket, add this to the file:

{
 "hosts": ["tcp://0.0.0.0:2375","npipe://"]
}

Other options for the configuration file for Docker in Windows are documented here: Miscellaneous Options. For example you can specify a proxy server to use when pulling images from the Docker Hub.

Just to add complexity:

  • the Docker service will not start if the same parameter is set in service startup and in the configuration file
  • You can change the location of the configuration file by specifying a parameter for the service:
    sc config Docker binPath= ""C:\Program Files\docker\dockerd.exe\" --run-service --config-file "[path to file]""

Ports 2375 (unencrypted) and 2376 (encrypted with TLS) are the standard ports. You will obviously want to use TLS in a production environment, but the Windows Docker package does not include the tools to do this. Standard Windows certificates can’t be used. Instead you will need to follow the documentation to create OpenSSL certificates.

Allow Docker Connection Through Firewall

Configure an inbound rule in the Windows firewall to allow TCP connections to the Docker service on port 2375 or 2376. This needs to be allowed for all profiles, because the container virtual interface is detected as on a Public network.

netsh advfirewall firewall add rule name="Docker" dir=in action=allow protocol=TCP localport=2375 enable=yes profile=domain,private,public

Note that, by default, containers do not have access to services and sockets on the host.

Pull the Portainer Image

Back in an elevated PowerShell console, pull the current Portainer image from the Portainer repository in the Docker Hub:

docker pull portainer/portainer

If we look in the images folder in C:\ProgramData\docker\windowsfilter we can see that we have downloaded 6 new layers. We already had two Nano Server layers, because we pulled those down previously.

Portainer Layers

If we look at the image history, we can see the layers making up the image:

docker image history portainer/portainer

Portainer Image History

The two base layers of the Portainer image are Windows Nano Server. We already had a copy of the Nano Server base image, but ours was update 10.0.14393.1593, so we have downloaded a layer for the newer update 10.0.14393.1715. We can also see the action that created each layer.

If we inspect the image, with:

docker image inspect portainer/portainer

we can see some of the things we need to set it up

  1. The container is going to run portainer.exe when it starts
  2. The exposed port is 9000
  3. The volume (or folder) to mount externally is C:\Data

Set up Portainer container

Quick version:

  1. Create a folder in the host called: C:\ProgramData\Containers\Portainer
  2. Open an elevated PowerShell console on the host
  3. Run this command:
    docker run -d --restart always --name portainer -v C:\ProgramData\Containers\Portainer:C:\Data -p 9000:9000 portainer/portainer

The long version is: we need the command line to run the Portainer image:

  1. Standard command to create a container: docker run
  2. We want to run the container detached as a free standing container, with no attached console: -d or --detach
  3. There is no need to remove the container if it is stopped. Instead, we want to restart the container automatically if, for example, the host is rebooted: --restart always
  4. We can give the container a name, to make it easier to manage: --name portainer
  5. Portainer reads information about images and containers directly from Docker, so it does not need to store that. But it needs to store it’s own configuration, for example settings and user passwords. To do this, we need to save the configuration data outside the container.  We can do this in Docker by mounting an external folder in the file system of the container. The folder in the container has already been designated as C:\Data in the image, but the folder in the host can be anything you choose. In this example we are using C:\ProgramData\Containers\Portainer. The folder needs to exist before using this: -v C:\ProgramData\Containers\Portainer:C:\Data
  6. The Portainer process is listening on port 9000 (see above). We can connect to this directly from the host itself, without doing anything more. But the outside world has no access to it. The container is running on a virtual switch with NAT enabled. This does port forwarding from the host to the container. We need to decide what port on the host we would like to be forwarded to port 9000 on the container. If we don’t specify a port, Docker will assign a random port and we can discover it through docker container inspect portainer. Otherwise we can specify a port on the host, which in this case can also be 9000: -p 9000:9000
  7. The image to run: portainer/portainer
  8. We don’t need to specify a command to run, since the image already has a default command: portainer.exe

Putting the parameters together, the full command is:

docker run -d --restart always --name portainer -v C:\ProgramData\Containers\Portainer:C:\Data -p 9000:9000 portainer/portainer

Connect to Portainer

Using a browser on your desktop, connect to the Docker TCP port on the remote host: http://192.168.1.144:9000. Set up a password for the admin user:

Portainer Setup

Set up the Docker host as the endpoint:

Portainer Setup Endpoint

Note that the endpoint is the IP address of the host virtual interface on the container subnet (in this case 172.17.64.1). This address is also the gateway address for the container, but in this context it is not acting as a gateway. The virtual interface on the host is listening on port 2375 for Docker connections.

And we are in:

Portainer Dashboard

We can also connect directly from a browser on the host to the container. For this, we need to use the IP address of the container itself, in this case 172.17.68.78, or whatever address we find from docker container inspect portainer.

The Portainer Container

We don’t need to set up a firewall rule to allow access to the container on port 9000. Docker sets up a bunch of rules automatically when the container is created:

Container Automatic Firewall Rules

These rules include: DHCP; ICMP; and DNS. They also include port 9000 on the host, which we specified would be forwarded to port 9000 in the container:

Container Automatic Firewall Rule for Portainer

In Portainer, when we set up the endpoint (being Docker on the host) we need to specify the virtual interface of the host that is on the same subnet as the container (the 172.17.64.1 address). This is because Windows does not allow the container to connect directly through the virtual interface to a service on the physical interface (192.168.1.144).

If we look at the TCP connections on the host, with: netstat -a -p tcp, we see that there is no active connection to Portainer in the container, although my browser is in fact connected from outside:

Portainer Host TCP Connections

However, if we look at the NAT sessions, with Get-NetNATSession, we see the port forwarding for port 9000 to the container:

Host Get-NetNATSession

Docker has attached a virtual hard disk to the host, being the file system of the container:

Host Disk Manager

If we give it a drive letter we can see inside:

Portainer Container System Drive

The portainer executable is in the root of the drive. C:\Data is the folder that we mounted in the docker run command. Other folders like css and fonts are part of the application. These are contained in the first layer of the image, after the Nano Server layers. The layer was created by the COPY command in the Portainer Dockerfile used to create the image:

FROM microsoft/nanoserver
COPY dist /
VOLUME C:\\data
WORKDIR /
EXPOSE 9000
ENTRYPOINT ["/portainer.exe"]

And here is the portainer process running on the host in Session 2, using:

Get-Process | Where-Object {$_.SI -eq 2} | Sort-Object SI

Portainer Process Running on Host

Security

You can see in the Portainer GUI for creating endpoints that we can connect to Docker with TLS. This assumes we have set up Docker with certificates and specified encrypted TCP connections, covered in the Docker daemon security documentation.

We should also connect to Portainer over an encrypted connection. We can do this by adding more parameters to the docker run command: Securing Portainer using SSL.

More about using Portainer

You can read more about using Portainer in the Portainer documentation.

Windows Containers: Properties

If we create an instance of an image in interactive mode, and run a PowerShell console in it, then we can see inside the container.

In a previous post I used the Nano Server image, because it is small and quick. But Nano Server is a cut down OS so, for the purposes of seeing how a container works, let’s take a look inside a Windows Server Core container. The question of when Nano Server can be used in place of Core is a subject for another time.

The Docker command to do this is:

docker run --rm -it --name core microsoft/windowsservercore powershell

The system information, with systeminfo, shows a Windows server where some of the properties belong to the container, and some to the host. For example, the language and locale belong to the container, but the BIOS and boot time belong to the host:

Container SystemInfo

The TCP/IP information, with ipconfig /all shows that the container has its own:

  • hostname
  • Hyper-V virtual ethernet adapter
  • MAC address
  • IP address in the private Class B subnet, which we saw previously was allocated to the Hyper-V virtual switch
  • gateway, which we saw previously was the Hyper-V virtual ethernet adapter on the host
  • DNS server addresses.

Container IPConfig All

I can connect to the outside world, with ping 8.8.8.8 and get a reply:

Container Ping World

The running processes, from Get-Process, show the PowerShell process, as well as what look like typical user processes. If I run Get-Process | Sort-Object SI I can see that there are two sessions: a system session in Session 0, and a user session in Session 2.

Container Get Process Sort SI

I can start other processes. For example, if I start Notepad, then I see it running as a new process in Session 2.

Container Start Notepad

The services, from Get-Service, show normal system services. It is easier to see if I filter for running services, with:

Get-Service | Where-Object {$_.Status -eq "Running"} | Sort-Object DisplayName

Container Get Service Filter and Sort

I have listening ports, shown with Get-NetTCPConnection, but nothing connected:

Container Get TCP Connection

There are three local user accounts, shown with Get-LocalUser:

Container Get Local User

PowerShell tells me that it is being executed by the user ContainerAdministrator:

Container Get Process PowerShell UserName

In summary, I have something that looks similar to an operating system running a user session. It can start a new process and it can communicate with the outside world.

Let’s see what it looks like from outside. From the host I can ping the container:

Host Ping Container

I can telnet from the host to port 135 (one of the ports that I saw was listening) in the container, and make a connection:

Host Telnet Container

But I can’t make a connection from outside the host. I already know there is no route to the container subnet. What happens if I supply a route? Still no reply. I am not really surprised. The connection would have to go through the host, and there is nothing in the host firewall to allow a connection to the container.

World Ping Container

If I start another container, though, it can ping and get a reply from the first container:

Container Ping Container

If I look in Task Manager on the host, there is no obvious object that looks like a container. I don’t even know what size I would expect it to be. But I notice that the PowerShell process in the container shows as the same process on the host.

Get-Process PowerShell in the container:

Container Get Process PowerShell

Get-Process PowerShell on the host:

Host Get Process PowerShell

The process ID 3632 is the same process. All three PowerShell processes, including the one in the container, are using the same path to the executable. You could say that the container is a virtual bubble (session, namespace or whatever you want to call it) executing processes on the host:

Host Get Process PowerShell Path

If I look at all the processes on the host, I can see that the container’s Session 2 is also Session 2 on the host. Here are the host processes filtered by session:

Get-Process | Where-Object {$_.SI -eq 0 -or $_.SI -eq 2} | Sort-Object SI

Host Get Process Filter and Sort SI

Session 0 (the System session) has a lot more processes than shown inside the container, but Session 2 is the same. Processes like lsass, wininit, csrss are the normal processes associated with a session.

The host does not see the user who is executing the processes. In the container the user is ContainerAdministrator, but there is no such user on the host, and the host does not have the username:

Host Get Process PowerShell UserName

A container is ephemeral. But if I create files inside the container they must be stored somewhere.

In the image folder of the host I can see a new layer has been created:

Docker Images Folder

The layerchain.json file tells me that the layer is chained to the Windows Server Core base image layers. The layer has a virtual hard disk drive called “sandbox”, which sounds like the kind of place that changes would be saved.

If I look in Disk Manager, I can see that a new hard disk drive has been attached to the host:

Host Disk Manager

The disk is the same size as the apparent system drive inside the container. It is shown as Online, but with no drive letter. However, if I give it a drive letter, then I can see the same file system that I was able to see inside the container:

Container Sandbox Disk on Host

So the file system of the container is created by mounting a Hyper-V virtual hard disk drive. This only exists for the lifetime of the container. When the container is removed, any changes are lost.

In summary:

  • From inside, the container appears to have similar properties to a normal virtual machine.
  • The container has a network identity, with a host name, virtual Ethernet adapter and IP address.
  • It can connect to the outside world, and with other containers, but the outside world cannot (until we change something) connect to it.
  • It has a file system, based on the image the container was created from.
  • On the host, the container processes are implemented as a distinct session.
  • The file system of the container is implemented as a virtual hard disk drive attached to the host.
  • Files can be saved to the virtual hard disk drive, but they are discarded when the container is removed.

Windows Containers: Run an Image

A container is an instance of an image. When we “run” the image, a container is created. Let’s see what happens when we do this.

In previous posts I covered installing the Windows Containers feature, and downloading a base image of Windows Nano Server or Windows Server Core.

Docker is the daemon or service that manages images and containers. It is managed at the command line, in PowerShell or the Command Prompt. To use Windows Containers we need to get familiar with the Docker commands.

I am using the base image of Nano Server as an example, because it is simple and small. When you see how it works, it is easy to imagine how other images based on Windows Server Core might also work.

Lets just run the Nano Server image and see what happens. In an elevated PowerShell console:

docker run microsoft/nanoserver

The console blinks, briefly changes to C:\ prompt, then returns to the PowerShell prompt. It seems that nothing happened at all!

Docker Run Nano

We can try:

docker container ls

to see if any containers exist. It shows none. But:

docker container ls -a

(or –all) shows a container that has exited.

Docker Container LS

So there was a container but it exited. I can see that the container has an ID, and a name.

I can start the container with:

docker start [ID]

but it exits again. Clearly it is configured to do nothing and then exit.

Docker Start Container

This container is no use to me, since it just runs and exits. I can remove it with:

docker container rm [ID]

Docker Container Remove

How can I get it to hang around, so I can see what it is? Normally a server waits for something to do, but this container seems to exit if it has nothing to do. It acts more like a process than a server. I could try giving it a command that continues until stopped, like:

docker run microsoft/nanoserver ping -t 8.8.8.8

Now I can see that the container continues to perform the ping. If I disconnect the terminal with Ctrl+C, the container is still running.

Docker Run Nano Ping

If I run:

docker container attach [ID]

then the PowerShell console attaches again to the output of the running ping process.

Docker Container Attach

I need to run:

docker container stop [ID]

to stop the ping process, and:

docker container rm [ID]

to remove the container.

If I want to run a container and see what it is doing, then I can run an interactive container. Putting the commands together:

    • create the container:
docker run [image]
    • remove it when it exits:
--rm
    • double dash is for a full word, or an abbreviation:
--
    • single dash is for a concatenation:
-
    • so -[interactive][tty] is:
-it
    • give the container a name so that I don’t have to find the ID or the random name:
--name [friendly name]
    • a command parameter at the end is the executable to run in the container:
powershell

So:

docker run --rm -it --name nano microsoft/nanoserver powershell

gives me a running container with an attached PowerShell console:

Docker Run Interactive

Now we can see the inside of the container as well as the outside, and get a good idea of how it works.

Windows Containers: Base Images

The Containers feature on Windows Server 2016 runs applications in containers. A container is an instance of an OS image. Let’s explore what an image is.

For Windows containers we can start with one of two base images:

  1. Windows Server Core
  2. Windows Nano Server

The base images are provided by Microsoft, and kept in the Microsoft repository in the Docker Hub registry.

To get a copy of the current Nano Server base image, we use the command:

docker pull microsoft/nanoserver

This downloads, unzips and saves the image in the Docker folder at C:\ProgramData\docker\windowsfilter.

  • Docker commands are run by the docker client from either the Command Prompt or PowerShell
  • The command processor must run elevated
  • The place where the images are stored, by default, can be changed in the configuration of Docker
  • By default Docker pulls the latest version of the image. Other versions can be specified explicitly.

An image is a set of files. Here are the image files for Nano Server:

Nano Image Base Layer

The image consists of files and registry hives. Here are the contents of one of the folders for the Nano Server image:

Nano Image Folder

The files look like a standard system drive:

Nano Image Files

The Hives folder is a collection of registry hives:

Nano Image Registry Hives

You can load the registry hives into Regedit in the normal way:

Nano Image Registry Software Hive

We also have a Utility VM folder with two Hyper-V Virtual Hard Disk (vhdx) files:

Nano Image Utility VM

These are used when the container is run in a small Hyper-V virtual machine instead of directly on the host OS (Hyper-V isolation mode).

In my example of the Nano Server base image, there were two folders:

Nano Image Pull

Each folder represents a layer. When an image is modified, the changes are saved in a new layer.

The command:

docker image ls

shows one image:

Nano Image List 1593

The command:

docker image history microsoft/nanoserver

shows two layers. The first layer is the original release of Nano Server, 10.0.14393.0, and the second layer is an update, 10.0.14393.1593. You can see the name, date, action that created it, and size of each layer:

Nano Image History

The command:

docker image inspect microsoft/nanoserver

shows the details of the image. These include:

  • The unique ID of the image
  • The OS version
  • The unique ID of each of the two layers

If we look back at the Microsoft repository on Docker Hub, we can see the tags for different updates:

Update 10.0.14393.1066
Update 10.0.14393.1198
Update 10.0.14393.1358
Update 10.0.14393.1480
Update 10.0.14393.1593
Update 10.0.14393.1715

Update 1715 is newer than the one I pulled recently. If I run the command:

docker pull microsoft/nanoserver

again, I get the latest image. If I run the command with a tag appended, I get that specific image. In this case they are different update levels, but they could be different configurations or any other variation.

Now a third folder is added in C:\ProgramData\docker\windowsfilter:

Nano Image Pull 1715

The command

docker image ls

shows that I have two images:

Nano Image List 1715

The command:

docker image history microsoft/nanoserver

again shows two layers in the latest image. One layer is the new update, and the other layer is the same original layer as in the previous version:

Nano Image History 1715

The image name “microsoft/nanoserver” refers, by default to the latest version of the image, consisting only of the original layer and the newest layer. Docker keeps track of images and layers in a local database:

Docker Local Database

Summary:

  1. Windows containers are instances of an image
  2. An image is a set of files and registry hives
  3. An image comprises one or more layers
  4. All Windows container images start from either Windows Server Core or Nano Server
  5. The layers may comprise updates, roles or features, language, applications, or any other change to the original OS.

Windows Containers: Add Feature

The Windows Server 2016 Containers feature enables Windows Server 2016 to run applications in “containers”. Let’s take a look at what this feature is.

There are plenty of guides on the Internet for how to set up containers on Windows. The purpose here is not so much to provide the instructions, as to see and understand how the new Containers feature is implemented.

Step 1: Build a standard Windows server. It can be a physical or virtual server.

Step 2: Install the Containers feature.

Windows Containers Feature

This creates a new service: the Hyper-V Host Compute Service. Note that several Hyper-V components are already installed by default in the server OS, without adding the Hyper-V role explicitly. The Containers feature extends the default Hyper-V services.

Hyper-V Host Compute Service for Containers

The Hyper-V Host Compute service is the one that will partition access to the Windows kernel by different containers.

Next, install the PowerShell module for Docker. There are two steps to obtain the module:

  1. Add the Microsoft Nuget module
  2. Add the PowerShell Docker module.

Nuget is the Microsoft package manager for open source .NET packages:

  • Install-PackageProvider -Name NuGet -Force

Then the PowerShell module for Docker:

  • Install-Module -Name DockerMsftProvider -Repository PSGallery -Force

Next, we need to add the Docker components. Docker is a third party application that manages containers, on Linux and now on Windows. Microsoft provides the API (in the Hyper-V Host Compute Service) and Docker provides the application that uses the API to run containers. The documentation for Docker comes from Docker, not from Microsoft. The command to install the Docker package is:

  • Install-Package -Name docker -ProviderName DockerMsftProvider

I have broken these out as separate steps for clarity. If you install the PowerShell Docker module you will be prompted first for Nuget. The Docker package (last step above) will also add the Containers feature, if you have not already done it.

Docker is installed as a service (daemon) and a client to operate the service.

Docker Daemon Service

The Docker installation has these two executables.

Docker Executables

The file dockerd.exe is the Docker service.

Docker Properties

The file docker.exe is the client. Like a lot of open source tools, Docker is managed at the command line. You can run the docker client executable in the Command Prompt.

Docker Client

The Containers feature also creates an internal network where the containers will run by default. This consists of:

  1. A Hyper-V virtual switch
  2. A subnet used for the virtual network (always 172.17.nnn.0/20)
  3. A virtual NIC on the host server that is presented to the virtual switch
  4. Two new rules in the Windows firewall.

By default the Containers feature sets up a NAT switch. A Windows component, WinNAT, maps ports on the host to IP addresses and ports on the container network.

Here is the virtual switch:

Docker Virtual Network

And the NAT component:

Container VMSwitch and NAT

The host NIC on this virtual switch:

Hyper-V Virtual Ethernet Adapter

 The Hyper-V Virtual Ethernet Adapter shown in the normal Network and Sharing Centre:

Hyper-V HNS Internal NIC

You can create other types of virtual switches later.

The installation also creates two default firewall rules:

Docker Automatic Firewall Rules

The Inter- Container Communication (ICC) default rule allows anything from the virtual container network:

Docker Automatic Firewall Rules ICC to Docker Network

and RDP:

Docker Automatic Firewall Rules RDP

It is not obvious why the Containers feature creates a firewall rule for RDP. It does not enable RDP on the host. And the containers do not support RDP.

In summary:

  • The Windows Containers feature is enabled as an extension of the default Hyper-V services.
  • The Hyper-V Host Compute Service allows containers to run processes on the Windows kernel. The Hyper-V Host Network Service creates the internal logical networks for the containers.
  • There is no need to install the Hyper-V role itself, unless you want to run containers in a VM (called Hyper-V Isolation Mode).
  • Docker is a third party application that uses the Windows Containers feature to create and run containers.
  • The Docker package installs the Docker components on top of the Windows Containers feature.
  • The Docker package installation also creates a virtual network for containers. This has a Hyper-V virtual switch with NAT networking, and a Hyper-V virtual NIC on the host attached to the switch.

So far, we have installed the Containers feature and the Docker components. We still can’t do anything until we obtain an image to create containers from.

Azure Domain Join

As well as doing large scale IT infrastructure projects, I also support a few small businesses run by friends. In one of them, for over a decade, they have had a server on site. Now they don’t. Everything is done in Azure.

They started with Microsoft Small Business Server. This provided Active Directory, Exchange, and File and Print. Over several years we moved to hosted e-mail, then Office 365. In this last stage we moved the PC’s from the local domain to the Azure domain. Users now sign in with Windows Hello, using a PIN. All the shared data is in SharePoint Team Site. All the personal data is in OneDrive. The local Special Folders on the PC are redirected to OneDrive. They use Skype, Yammer, Delve to work together, on iPad or PC. They can work at home or in the Office. Management of the PC’s is done with Intune.

Most of all, the server is switched off. No-one needs to come on site for hardware problems. Anyone can provide support, from anywhere, if they know Office 365 and Azure.

The Azure domain is not quite the same as a local domain. There is no Group Policy. If you wanted, you could add GPO’s with Azure Active Directory Premium, but it is not cheap, and of course you need some skills to manage it. It got me thinking about how we could replace GPO’s.

In one of my large scale assignments recently, where we rolled out a new global desktop, we actually needed only a few GPO’s. We had a big and complex policy to make Internet Explorer compliant with security standards. We had policies for certificates, wireless networking, passwords. But it was not very many. Without GPO’s we would need another way to do these configurations. But it would not be enough to justify keeping a global Active Directory infrastructure.

The problem with certifications

Certifications sound like a great idea, and if I were in HR recruiting IT people, I could be forgiven for thinking that they tell me something important about a person’s skills level. But I would be wrong.

The idea of certifications is not wrong. If I were having a boiler installed, I would probably want the technician to be certified to work with gas. This would be an industry certification, perhaps with an independent assessment body. They might also have done some training for the specific type of boilers they install. The IT industry does not do this. It has vendor certifications that are intended to demonstrate a skill level with a specific technology:

  • Cisco Certified Internetwork Expert (CCIE) and Cisco Certified Design Expert (CCDE)
  • Microsoft Certified Solutions Expert (MCSE)
  • VMware Certified Design Expert (VCDX)

The certifications are hard. Anyone who has a CCIE certification has demonstrated the ability to study and has the aptitude to pass a certain type of exam. They may also have been fortunate to have an employer willing to pay the steep fees for courses. The question, however, is whether they demonstrate real expertise in the technology.

The problem is that the course material is created with the idea of enabling an exam, and the exam is created purely as a test of the course material. An example will show what I mean.

This example is taken from the Cisco material for TSHOOT. This is one of the exams for the Cisco Certified Network Professional (CCNP) Routing and Switching certification. It covers the skills for troubleshooting and maintaining Cisco IP Networks. Cisco certifications are some of the best, so this example is not an adverse comment on Cisco. It is just an example of a certification topic.

Troubleshooting an IP network requires a good understanding of TCP/IP, and how packets flow through a network from server to switch to WAN and client, and back to the server. NetFlow is a way of recording information about flows, so that you can diagnose performance problems. There is quite a lot you need to know about flows in order to diagnose problems. The course material tells us that:

"A flow is a unidirectional stream of packets, between a given source and a destination, that have several components in common. The seven fields that need to match for packets to be considered part of the same flow are as follows:

  • Source IP Address
  • Destination IP Address
  • Source Port (protocol dependent)
  • Destination Port (protocol dependent)
  • Protocol (Layer 3 or 4)
  • Type of Service (ToS) Value (differentiated services code point [DSCP])
  • Input interface."

I suppose there are a number of concepts here. One is that the flow is a specific "conversation" between client and server. Now this is a bit surprising. It says "unidirectional". Does that mean that the response to a request is in a different flow? How can I tell if there is a network or server delay if the request and response are in different flows? Another concept is that you can’t jump between interfaces. You might have more than one network connection to a switch, but those would be separate flows. I don’t really need to know that there are precisely seven fields: I can always look that up. And I don’t need to know trick questions about what might be a field but is not. TCP/IP flows is a really interesting topic, and I would like to know a bit more about it.

Now here is the test question:

"Which of the following is not a NetFlow key field

  • Source IP Address
  • Layer 4 Source Port
  • ToS Byte (DSCP)
  • TTL
  • Input Interface."

Did you notice what happened there? I don’t need to know anything about flows. I just need to remember the list of seven fields. And I need to be aware of trick answers. Is Source Port really Layer 4? Is TOS value really a byte? Did I just forget TTL, or could there be a reason why Time to Live is a field that I have forgotten? None of this matters in the real world. In the real world we switch on NetFlow, and configure a collector like SolarWinds. The real work is in interpreting the NetFlow data. And NetFlow is expensive. And it can’t tell you what is happening on the parts of the WAN you do not control. And it does not tell you what response time the user actually experiences.

The problem here is the methodology. If the exam were in Algebra, there would be a vast body of knowledge, different course material, trained teachers and professional examiners. But there is no such body of knowledge or of educators for troubleshooting an IP network. Cisco has to get someone to prepare a course and someone else to prepare an exam. The exam is a test of the course.

Certification courses provide useful training. And simple exams that test whether you paid attention are OK. But certifications do not prove skills. They prove a willingness to study, and an aptitude for a certain kind of test.

Windows 10 S for Enterprise?

Windows 10 S is the new edition of the client OS that is restricted to run only applications from the Windows Store. The advantage is that it is more stable and secure than an OS where the user can install software from anywhere. Microsoft has positioned the OS for the education market. But perhaps it has possibilities for the enterprise too.

Windows 10 S was released in May 2017. It is only available as an OEM installation, for example in this Microsoft Surface Laptop.

Surface_L_Pivot-Blue-pos2_V1

Vendors with Windows 10 S laptops currently include Dell, HP and others. Prices are in a similar range to other laptops and notebooks.

The marketing from Microsoft is aimed at the education market, but what interests me is the scope for using Windows 10 S in the enterprise. Mobility is costly, and this OS might bring the cost down.

The main problem for enterprise mobility is making it secure. One approach to this is the managed laptop:

  • a custom Windows 10 Enterprise image
  • joined to the domain
  • encrypted
  • authenticated by a certificate
  • no admin rights for the user, OR admin rights with more active detection and blocking
  • SSL VPN client
  • web proxy client.

This has more complexity and higher support costs than a standard desktop.An alternative approach is to do away with the idea of validating the device at all, and provide access to enterprise data and applications only through a virtual desktop. In this case mobility is provided by any device running the remote access software: like Citrix Receiver or the VMware Horizon client. It can be a Mac, a Chromebook or a mobile thin client. The problem here is that, if you want to work offline, you need to store data and you need local applications. If you do that, you again need a managed device, and you add further costs.

Windows 10 S may provide a new option. Use a regular desktop in the office, and a Windows 10 S laptop for mobility. As the Windows 10 S laptop cannot run applications except from the Windows Store, the level of protection and additional support required is much lower. You can still run Office applications like Outlook. You can still edit a PowerPoint presentation or work on an Excel spreadsheet offline. But the scope for malware is much reduced. If you need to use an enterprise application like SAP when working from home, say, then you can use remote access to connect to a virtual desktop or a published application. But in this case the virtual desktop needs to be provided only to the mobile users and not to all users.

Windows 10 S supports these enterprise features:

  • Trusted Platform Module (depending on the OEM hardware)
  • Certificate Store for enterprise certificates
  • BitLocker disk encryption
  • Azure domain join and Windows Hello authentication
  • mobile device management with Intune, AirWatch or similar
  • desktop applications from Microsoft, Adobe, etc. as long as they are available from the Windows Store.

The typical company laptop is an expensive compromise. It needs to be powerful enough to run enterprise applications, light enough to carry around easily, secure enough to hold enterprise data, flexible enough to allow the user to work offline. I think on balance I would prefer to use a regular desktop in the office, and a Windows 10 S laptop for mobility.

OneNote and OneDrive

Have you tried using OneNote recently? It is a free product from Microsoft, but it rarely gets a mention. Combined with OneDrive, it is a good tool for keeping track of different types of information related by topic.

OneNote has been around since 2002. It is one of those products that you don’t hear much about, and it is easy to overlook. But it is a very useful tool for keeping track of different types of information related by topic. For example, let’s suppose you find a good article online. You want to make a note of the author, the URL, the key points and a graphic. Maybe you have other notes on the same topic. How do you do it, and where do you keep it?

You might try Notepad; but you can’t save the image or a hyperlink there. You could use MS Word, of course. Now you have a document. But how would you relate it to other material on the same topic: all in one document; or using different documents in a folder? And how you would you add something new from your mobile?

OneNote organises information in a hierarchy of Notebook, Section within Notebook, and Page within Section. You can move sections and pages around, if you want to reorganise. You can make links between sections and pages. In this sense it acts like a Wiki.

OneNote Example

You can use different types of material: text, images, tables, audio and video files, hyperlinks, file attachments.

OneNote Insert

You can also use OneNote as the notes manager for Outlook items, like appointments, contacts or tasks. The Outlook plugin adds OneNote to the menu bar, and lets you choose which notebook to save notes in.

Outlook Ribbon

From the notification area on the desktop taskbar you can make "quick notes" without opening OneNote.

OneNote Notification

This opens a note with a cut down menu.

Quick Note

In Edge you can use the OneNote Web Clipper to clip pages or parts of web pages and put them straight into notebooks. For example, here we are clipping a piece of a web page from Wikipedia:

OneNote Clip

The screenshots shown here are from the free version included with Windows 10. Office 365 has an enhanced version: for example you can add a spreadsheet item instead of a simple table.

When you open OneNote, you sign in with a "Microsoft" account, either a personal account at live.com or a business account through Office 365. You can add more than one account so, for example, you could share a Travel notebook between your personal and your business accounts. You only need to open the notebooks you choose, so at work you could open a Projects and a Travel notebook, while at home you could open a Travel and a Family notebook.

OneNote notebooks are saved automatically in OneDrive, the online personal datastore. This makes them accessible from anywhere, provided your security settings allow it. You can open your notebooks from Windows, Mac, iPad, Android and Windows Mobile clients. So, if you are away from your desk and you want to make a note, you can save it in the right notebook instead of hunting around for it later.

You can also share notebooks. You can share with Edit or View rights. The sharing is managed through OneDrive permissions, and you can manage the sharing in OneNote or OneDrive.

Share Notebook

OneNote is a good example of a simple idea developing over time into a useful tool. Do you remember Groove? Groove was a tool created by Ray Ozzie, creator of Lotus Notes. Groove Networks was founded in 1997, and acquired by Microsoft in 2005. Groove allowed document synchronisation and sharing, where both parties connected through a broker. Ray Ozzie later became Chief Software Architect at Microsoft., where he started the services that became Azure. The broker was the forerunner of SaaS services, and Groove was the forerunner of OneDrive. Now OneNote and OneDrive do more or less what Groove used to do, but in a simpler and more versatile way.