Home Software Blog Wallpapers Webtools
Windows 2016 Containers Part-1
Thursday 29, December 2016   |   Post link   |   Sample code  Download related material

Containers seem to be the hot topic now-a-days. Though late in the game, Microsoft finally has added support for containers. Support for containers and Docker have been there in the various CTPs of Windows 2016 & even Windows 10 insider builds & the anniversary update. This post however will use Windows 2016 RTM only. There is more than enough information on containers in general so I won't spend too much time on that but concentrate on using Docker on Windows to work with containers.

Just to recap - Containers are isolated, resource-constrained and portable operating environment for applications. The magic of isolating and constraining resources is not something Docker does on its own, it depends on the operating system to provide these capabilities.

On Windows, you can create two types of containers:

  • Windows 2016 server containers (works on Windows 2016 only)
  • Windows Hyper V containers (works on Windows 2016 as well as Windows 10)

This post will be talking only about Windows 2016 containers, I call these 'true' containers as there is no virtual machine (hypervisor layer) involved.

To get started with using containers, you can download a trial edition of Windows 2016 Server from here. The best option is to install Windows 2016 server (with desktop experience) as a virtual machine using VMWare or Virtual Box or Hyper-V. If you are planning to install it directly on your hard-disk, make sure you have drivers especially network/wireless-adapter drivers which will work on Windows 2016. My own experience wasn't very positive, Windows 10 drivers for my wireless-adapter did not work on Windows 2016 so I ended up wiping the parition clean off Windows 2016.

Here is what you need to get started with containers on Windows 2016 server:

  1. Install Windows 2016 with desktop experience
  2. Install Docker using the following PowerShell commands.
    Install-PackageProvider -Name NuGet -MinimumVersion -Force
    Install-Module -Name DockerMsftProvider -Force
    Install-Package -Name docker -ProviderName DockerMsftProvider -Force
    Restart-Computer –Force
    Note: this did not work for me, Docker package kept failing, here is a workaround for that:
    Download the Docker binaries directly from this link.
    Unzip both dockerd.exe and docker.exe to a folder.
    Add the folder to the system path.
    Register Docker daemon to run as a service by entering 'dockerd --register-service' at the command prompt (with Administrator privileges).

Getting the base OS image

Now that we've got Docker daemon running, we need to download the base operating system image. Prior to this when I had used CTP5, I used the PowerShell command

Install-ContainerImage -Name WindowsServerCore
In this post, I'll use Docker's own command to get the image:
docker pull microsoft/windowsservercore
Note, both commands end up downloading 5 GB or more worth of bytes.

Running the image

If all went well and the base OS image is downloaded, you should be able to see the image using the following Docker command docker images. List Docker Images 'microsoft/windowsservercore' is the base OS image. As you create additional images, those will be listed too. Now let's run the image:

c:\>docker run -it microsoft/windowsservercore cmd.exe
The above command will run a containerized version of cmd.exe. Instead of cmd.exe you could have started PowerShell.exe. The '-it' switch runs the containers in an interactive mode for e.g. while in the command prompt, you can run PowerShell or start other processes, all these will be run within the container. Try and run the DIR command on C:\Program Files, you'll see a very small set of install applications unlike what you have on your container's host.

Cmd running in a container

You can use the 'docker ps' command to list all running containers:

Listing containers

In the image above you can see that I have two containers running. Each time a container runs, it gets a unique ID (container id) and also a name, in the image you can see the two names 'sick_bell' & 'focused_babbage'. To work with any of the containers, use the 'docker container' command e.g. 'docker container --help'.

Cmd running in a container

It's usually a good idea that whatever process that is running within a container shuts down on its own. What I mean is, if you're running a service, it would be a good idea to have a way to send a 'stop' command to shut the process down instead of using docker's container commands like stop. To end the container you started, enter EXIT at the command prompt.

Running you own service in a container

Now that we know how to run a container from an image, let's try to containerize our own application. For this post, I'll use a sample service application called TWS (time webserver) which is a .NET exe that listens on a particular port. It responds to request for retrieving the server time, printing the current logfile and request to stop. The source code plus exe can be downloaded from here. To use this application, we need a way to copy this exe to the container which can be done in many ways. For this post, I have copied this exe to my physical machine's IIS within a directory called 'software'. This means that I am using the host machine within which Windows 2016 is running as a virtual machine. Why am I not using the virtual machine's IIS? This is because of a current bug whereby the container's host's IP address is not accessible from a container on Windows - weird. Moving on, ensure anonymous authentication is enabled for the 'software' folder so we can easily access the file from HTTP from the container.

Hosts IIS setting

With that set, lets now prepare to run our tws server in a container. Open an new command prompt in Windows 2016 Server:

C:\Users\Administrator>docker run -it microsoft/windowsservercore cmd.exe
Pressing enter will start the container and you'll now be in the container's command prompt. Keep the host machine's (not the Windows 2016 virtual machine but the physical machine's) IP address handy and enter the following command in the container's cmd prompt:
C:\>mkdir c:\tws
C:\>cd c:\tws
c:\tws>PowerShell -Command (New-Object System.Net.WebClient).DownloadFile('', 'c:\tws\tws.exe')
c:\tws>tws -port 8001 -logfolder c:\tws

If all goes well, you should have the tws application running like shown below:

Service running in the container

Tws.exe prints the URL from where it can be access when it starts as shown in the screenshot above. While in Windows 2016, start a web browser and navigate to the URL printed by TWS, you should see a response like this:

Service running in the container

Each time a request is received, TWS write a log entry to a file. These entries can be requested by appending '/viewlog' to the same URL e.g.:

Service running in the container

An interesting thing to note is that IP address in the URL printed by TWS; this IP address is a dynamic IP addressed assigned to the container which is accessible only from the container's host operating system which is our Windows 2016 server. If you want to make this application accessible to other machines you need to use the -p option of Docker. Get back to the container and press ENTER to shut down TWS. Enter exit to shut down the container.

We'll now use the '-p' switch to make our service available to devices other than the container host. Just like before start the container using docker's run command but this time tell Docker to map port 8001 of the server (the first part of 8001:8001) to the container 8001 port; needless to say both the port can be different if you want. .

C:\Users\Administrator>docker run -it -p:8001:8001 microsoft/windowsservercore cmd.exe

Now in the container's cmd prompt, enter the following:

C:\>mkdir c:\tws
C:\>cd c:\tws
c:\tws>PowerShell -Command (New-Object System.Net.WebClient).DownloadFile('', 'c:\tws\tws.exe')
c:\tws>tws -port 8001 -logfolder c:\tws

You shoud now be able to access the TWS server from outside the container's host (the Windows 2016 machines/virtual machine) by replacing the container's IP address with the container host's IP address.

Building our own image

Now that we know our service is working fine within a container, let's create an image out of it so that all the changes we've made are persisted and next time on we won't have to download the service first.

I have decided to name my image sids/tws2, you can choose your own name. Shut down the container by going back to the container's command prompt and pressing ENTER to stop the service and then run the exit command to exit the command prompt which automatically shutsdown the container. Let's now see the list of container we have been running:

docker ps -a

The above command will show you all containers that are or have been running as shown in the screenshot below:

List all containers

We want to create an image from the last container which we ran. Note down the container ID of the first row and use the Docker commit command:

docker commit 24cda6150c2f sids/tws2

Note: replace 24cda6150c2f with the ID on your system. Now run the docker images command to check if your image is in the list, it should be. You now have a service ready to run in your new image.

Our own image

This is one way to create an image. The other way is to script the image creation which I'll cover in the next post along with how to persist data in the same post.

Sample code  Download related material


Posts By Year

2023 (5)
2022 (10)
2021 (5)
2020 (12)
2019 (6)
2018 (8)
2017 (11)
2016 (6)
2015 (17)
2014 (2)
2013 (4)
2012 (2)

Posts By Category

.NET (4)
.NET Core (2)
AWS (5)
AWS API Gateway (1)
Android (1)
Apache Camel (1)
Architecture (1)
Audio (1)
Azure (2)
Book review (3)
Business (1)
C# (3)
C++ (2)
CloudHSM (1)
Containers (4)
Corporate culture (1)
Database (3)
Database migration (1)
Desktop (1)
Docker (1)
DotNet (3)
DotNet Core (2)
ElasticSearch (1)
Entity Framework (3)
Git (3)
IIS (1)
JDBC (1)
Java (9)
Kibana (1)
Kubernetes (1)
Lambda (1)
Learning (1)
Life (7)
Linux (1)
Lucene (1)
Multi-threading (1)
Music (1)
OData (1)
Office (1)
PHP (1)
Photography (1)
PowerShell (2)
Programming (28)
Rants (5)
SQL (2)
SQL Server (1)
Security (2)
Software Engineering (1)
Software development (2)
Solr (1)
Sql Server (2)
Storage (1)
T-SQL (1)
TDD (1)
TSQL (5)
Tablet (1)
Technology (1)
Test Driven (1)
Unit Testing (1)
Unit Tests (1)
Utilities (3)
VC++ (1)
VMWare (1)
VSCode (1)
Visual Studio (2)
Wallpapers (1)
Web API (2)
Win32 (1)
Windows (9)
XML (2)

Posts By Tags

.NET(6) API Gateway(1) ASP.NET(4) AWS(3) Adults(1) Advertising(1) Android(1) Anti-forgery(1) Asynch(1) Authentication(2) Azure(2) Backup(1) Beliefs(1) BlockingQueue(1) Book review(2) Books(1) Busy(1) C#(4) C++(3) CLR(1) CORS(1) CSRF(1) CTE(1) Callbacks(1) Camel(1) Certificates(1) Checkbox(1) CloudHSM(1) Cmdlet(1) Company culture(1) Complexity(1) Consumer(1) Consumerism(1) Containers(3) Core(2) Custom(2) DPI(1) Data-time(1) Database(4) Debugging(1) Delegates(1) Developer(2) Dockers(2) DotNetCore(3) EF 1.0(1) Earphones(1) Elastic Search(1) ElasticSearch(1) Encrypted(1) Entity framework(1) Events(1) File copy(1) File history(1) Font(1) Git(2) HierarchyID(1) IIS(1) Installing(1) Intelli J(1) JDBC(1) JSON(1) JUnit(1) JWT(1) Java(3) JavaScript(1) Kubernetes(1) Life(1) LinkedIn(1) Linux(2) Localization(1) Log4J(1) Log4J2(1) Lucene(1) MVC(4) Management(2) Migration history(1) Mirror(1) Mobile Apps(1) Modern Life(1) Money(1) Music(1) NGINX(1) NTFS(1) NUnit(2) OData(1) OPENXML(1) Objects(1) Office(1) OpenCover(1) Organization(1) PHP(1) Paths(1) PowerShell(2) Producer(1) Programming(2) Python(2) QAAC(1) Quality(1) REDIS(2) REST(1) Runtimes(1) S3-Select(1) SD card(1) SLF4J(1) SQL(2) SQL Code-first Migration(1) SSH(2) Sattelite assemblies(1) School(1) Secrets Manager(1) Self reliance(1) Service(1) Shell(1) Solr(1) Sony VAIO(1) Spirituality(1) Spring(1) Sql Express(1) System Image(1) TDD(1) TSQL(3) Table variables(1) Tables(1) Tablet(1) Ubuntu(1) Url rewrite(1) VMWare(1) VSCode(1) Validation(2) VeraCode(1) Wallpaper(1) Wallpapers(1) Web Development(4) Windows(2) Windows 10(2) Windows 2016(2) Windows 8.1(1) Work culture(1) XML(1) Yii(1) iTunes(1) renew(1) security(1)