5

I am running a Windows Container on a Windows host (Windows Server 2016 TP4).

The container shall run an IIS webserver on port 80 internally and I also want to bind port 80 to the host, so I can reach it via the host IP/URL.

I followed the instructions from Microsoft on

I tried both the approach via Powershell and Docker, and in both cases, the port binding to the host does not work.

========================= Powershell approach ==========================

Deploying container host to existing system (Windows Server 2016 TP4)

PS C:> wget -uri https://aka.ms/tp4/Install-ContainerHost -OutFile C:\Install-ContainerHost.ps1

PS C:> powershell.exe -NoProfile C:\Install-ContainerHost.ps1

Querying status of Windows feature: Containers...
Feature Containers is already enabled.
Waiting for Hyper-V Management...
Networking is already configured.  Confirming configuration...
Getting Container OS image (NanoServer) version 10.0.10586.0 from OneGet (this may take a few minutes)...
Container base image install complete.  Querying container images...
OS image (NanoServer) is already installed.
The following images are present on this machine:
    ContainerImage (Name = 'NanoServer') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']
    ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']

Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now tagged:
nanoserver          10.0.10586.0        8572198a60f1        5 months ago        0 B
nanoserver          latest              8572198a60f1        5 months ago        0 B
Script complete!

Preparing image and container that runs IIS (based on WindowsServerCore image)

These are the exact steps described in the Microsoft documentation at https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell. I create a container from WindowsServerCore, install IIS on it, and make a new image out of it, which I can then later reuse.

PS C:> Get-ContainerImage

Name              Publisher    Version      IsOSImage
----              ---------    -------      ---------
NanoServer        CN=Microsoft 10.0.10586.0 True
WindowsServerCore CN=Microsoft 10.0.10586.0 True


PS C:\> New-Container -Name TP4Demo -ContainerImageName WindowsServerCore -SwitchName "Virtual Switch"

Name    State Uptime   ParentImageName
----    ----- ------   ---------------
TP4Demo Off   00:00:00 WindowsServerCore


PS C:\> Get-Container

Name    State Uptime   ParentImageName
----    ----- ------   ---------------
TP4Demo Off   00:00:00 WindowsServerCore


PS C:\> Start-Container -Name TP4Demo

PS C:\> Enter-PSSession -ContainerName TP4Demo -RunAsAdministrator
[TP4Demo]: PS C:\Windows\system32> Install-WindowsFeature web-server

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
True    No             Success        {Common HTTP Features, Default Document, D...


[TP4Demo]: PS C:\Windows\system32> exit
PS C:\> Stop-Container -Name TP4Demo

PS C:\> New-ContainerImage -ContainerName TP4Demo -Name WindowsServerCoreIIS -Publisher Demo -Version 1.0

Name                 Publisher Version IsOSImage
----                 --------- ------- ---------
WindowsServerCoreIIS CN=Demo   1.0.0.0 False


PS C:\> Remove-Container -Name TP4Demo -Force

Now I have an IIS container ready that I bind to the "Virtual Switch".

PS C:\> New-Container -Name IIS -ContainerImageName WindowsServerCoreIIS -SwitchName "Virtual Switch"

Name State Uptime   ParentImageName
---- ----- ------   ---------------
IIS  Off   00:00:00 WindowsServerCoreIIS


PS C:\> Start-Container -Name IIS

PS C:\> Invoke-Command -ContainerName IIS {ipconfig}

Windows IP Configuration

Ethernet adapter vEthernet (Virtual Switch-30179F35-A9BD-4231-B264-BDD2994BD956-0):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::24f4:c726:ed9b:e603%28
   IPv4 Address. . . . . . . . . . . : 172.16.0.2
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . : 172.16.0.1

Adding port mapping and firewall rule:

PS C:\> if (!(Get-NetNatStaticMapping | where {$_.ExternalPort -eq 80})) {Add-NetNatStaticMapping -NatName "ContainerNat" -Protocol TCP -ExternalIPAddress 0.0.0.0 -InternalIPAddress 172.16.0.2 -InternalPort 80 -ExternalPort 80}

PS C:\> if (!(Get-NetFirewallRule | where {$_.Name -eq "TCP80"})) {New-NetFirewallRule -Name "TCP80" -DisplayName "HTTP on TCP/80" -Protocol tcp -LocalPort 80 -Action Allow -Enabled True}

Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host. (Just to be sure, I disabled the firewall on the host entirely.)

But the host port binding does not work. I cannot reach the IIS through the host IPs and bound port via http://localhost:80/ nor http://172.16.0.1:80/ nor http://10.10.0.79:80/

PS C:\> wget http://10.10.0.79:80/
wget : Unable to connect to the remote server
At line:1 char:1
+ wget http://10.10.0.79:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

PS C:\> wget http://172.16.0.1:80/
wget : Unable to connect to the remote server
At line:1 char:1
+ wget http://172.16.0.1:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

I can only reach the IIS default page via the container IP (http://172.16.0.2:80).

========================= Docker approach ==========================

And this is my approach using Docker to manage the container:

C:\> docker run --name iisbase -it windowsservercore cmd
C:\> powershell.exe Install-WindowsFeature web-server
C:\> exit
PS C:\Windows\system32> docker commit iisbase windowsservercoreiis
64271b60a1c4af29ce37ebcee45b00d824883eb67c717d4cee765d9f696867bb
C:\> powershell.exe "if(!(Get-NetFirewallRule | where {$_.Name -eq 'TCP80'})) { New-NetFirewallRule -Name 'TCP80' -DisplayName 'HTTP on TCP/80' -Protocol tcp -LocalPort 80 -Action Allow -Enabled True }"
C:\> docker run --name iisdemo -it -p 80:80 windowsservercoreiis cmd

At the end, I can only reach the IIS via the container IP, not via the host IP.

I'm using Docker version 1.10.0-dev, build 18c9fe0.

2 Answers2

1

Seems to be an issue with Windows Server TP4.

Stefan Scherer from the Docker team replied to my reported issue: https://github.com/docker/docker/issues/21558#issuecomment-202536462

I can reproduce the problems of @mathiasconradt. Played with the voting-app last week with TP4, I have the same workaround: Opening firewall ports on the host, opening the web server url with container's IP addresses. Can't wait to test the voting-app on TP5.

Waiting for TP5... meanwhile I use Apache httpd on the host to handle the port forwarding.

0

Note: Finally this is found to be a bug in Windows Server 2016 TP4 that causes the behavior described below (see the comments). Even though the Docker Daemon is supposedly installed, the client seems to be used instead with all the limitations described below. This bug may be fixed in the future TP5.


This is a limitation of the Docker implementation on Windows, where you cannot connect to the container through the host.

This is the answer for this same question on bug report #15740 : port exposure on windows = ? :

The reason you're having this, is because on Linux, the docker daemon (and your containers) run on the Linux machine itself, so "localhost" is also the host that the container is running on, and the ports are mapped to.

On Windows (and OS X), the docker daemon, and your containers cannot run natively, so only the docker client is running on your Windows machine, but the daemon (and your containers) run in a VirtualBox Virtual Machine, that runs Linux.

To connect to the container, you must connect to the IP-address of the virtual machine, not of your Windows computer.

This is all described in the Windows installation documentation, found here; http://docs.docker.com/installation/windows/.

The Virtual Machine is described in this section;
http://docs.docker.com/installation/windows/#learn-the-key-concepts-before-installing

And an explanation on how to map ports, and connect to them is explained here;
http://docs.docker.com/installation/windows/#container-port-redirection

I'm going to close this issue, because this is not a bug, and explained in the documentation. I hope the above explanation helps you.

harrymc
  • 498,455