I am running a Windows containerContainer using Docker on a Windows host (Windows Server 2016 TP4).
Note that I am using Windows Server 2016 (not any prior Windows
version), where Windows Containers can run natively without an
intermediate VM (no docker machine there) using Docker.
I followed the instructions
on
https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/inplace_setup
to setup the Windows container host (bare metal host, no Hyper-V, no
VM).
Specifically, this powershell script provided by Microsoft was
executed to setup the Windows 2016 container host
https://aka.ms/tp4/Install-ContainerHost, where it seems that all prerequisites regarding networking seem to be done.
Inside the container runs an IIS web server on the internal port 80.
I want to bind it to the host port 8800 (Windows Server 2016 TP4).
I followed the instruction as per:
https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker#create-iis-image-1-
and ran the The container like this:
docker run --name iisdemo -it -p 8800:80 windowsservercoreiis cmd
and had also added the firewall rules as pershall run an https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker#configure-network for ports 80IIS webserver on port 80 internally and 8800 beforehand. But I also turned off the Windows Firewall on the host entirely for testing purposes, justwant to be sure it's not conflicting.
As you can see from above docker callbind port 80 to the host, so I just made a slight change to the example given on the documentation page and changedcan reach it via the bound host port from 80 to 8800, so instead of -p 80:80
I run -p 8800:80
IP/URL.
When I run "ipconfig"followed the instructions from Microsoft on both host and container, I get:
I am either having a misunderstanding what the host is or something does not work right.
The documentation says:
When the container has been created, open a browser, and browse to the
IP address of the container host. Because port 80 (in my case it's
8800) of the host has been mapped to port 80 of the container, the IIS
splash screen should be displayed.
Unfortunately, this does not work.
I can reach the IIS via the container IP: http://172.16.0.2:80 but not via the host IP address http://172.16.0.1:8800 or http://10.10.0.79:8800.
(I also tried -p 80:80, and also that does not work; I cannot reach 172.16.0.1:80).
Running a docker port iisdemo
returns nothing:
PS C:\Windows\system32> docker port iisdemo
PS C:\Windows\system32>
and also docker ps
does not show anything under "ports".
docker inspect iisdemo
shows me:
"PortBindings": {
"80/tcp": [
{
"HostIp": "",
"HostPort": "8800"
}
]
},
...
"ExposedPorts": {
"80/tcp": {}
},
From my understanding, since I run docker "natively" from a Windows server with a Windows container, there is no intermediate VM (no docker machine) in between, so the "host" is the actual Windows Server that I run docker on.
So my question is, why does the host port binding not work? Why can I not reach the host as per Microsoft documentation? I tried both the approach via Powershell and Docker, but in both cases, the port binding to the host does not work.
What I also find confusing is that when I run netstat
on both the host and the containerFor now, I get the same results! netstat
onjust demonstrate the host does not show portsteps that I did with Powershell 8800
, but(but it does show port 80
, which should imho only appear when running netstat innot work with the container.Docker approach either):
netstat on Host:Deploying container host to existing system (Windows Server 2016 TP4)
PS C:\>netstat> wget -aburi |https://aka.ms/tp4/Install-ContainerHost findstr-OutFile "C:80"\Install-ContainerHost.ps1
PS C:> TCPpowershell.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:80.10586.0']
Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now test2016tagged:
nanoserver 10.0.10586.0 8572198a60f1 LISTENING 5 months ago 0 B
C:\>netstatnanoserver -ab | findstr ":8800" latest 8572198a60f1 5 months ago 0 B
C:\>Script complete!
netstatPreparing image and container that runs IIS (based on Container:WindowsServerCore image)
C:\>netstat -ab | findstr ":80"
TCP 0.0.0.0:80 test2016:0 LISTENING
TCP [::]:80 test2016:0 LISTENING
C:\>netstat -ab | findstr ":8800"
C:\>
And when I stop the container, the port 80 does not show anymore when I run netstat on the host. Why? It seems as if the network interfaces of host and container are the same.
I also read the documentation about NAT networking mode, although I must say, I am not a network expert.
https://msdn.microsoft.com/en-us/virtualization/windowscontainers/management/container_networking#port-mapping
I am not sure though whether this is relevant or not regarding the "Getting started: IIS demo", since it's not mentioned there or linked to at all. (I did not run any configuration commands mentioned there.) From my understanding, it should only be relevant for port forwarding when requesting from the host from an external IP address.
FYI - this is what I get when I run some Powershell commands about the virtual switch information on my host:
PS C:> Get-VMSwitch
Name SwitchType NetAdapterInterfaceDescription
---- ---------- ------------------------------
Virtual Switch NAT
PS C:> Get-NetNatStaticMapping
StaticMappingID : 16
NatName : ContainerNAT
Protocol : TCP
RemoteExternalIPAddressPrefix : 0.0.0.0/0
ExternalIPAddress : 0.0.0.0
ExternalPort : 80
InternalIPAddress : 172.16.0.2
InternalPort : 80
InternalRoutingDomainId : {00000000-0000-0000-0000-000000000000}
Active : True
and this is what I get withThese are the exact steps described in the Microsoft documentation at ipconfig
https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell. I create a container from WindowsServerCore, install IIS on hostit, and container:
ipconfig (Container):make a new image out of it, which I can then later reuse.
PS C:\Windows\system32>> ipconfigGet-ContainerImage
WindowsName IP Configuration
Publisher Version IsOSImage
Ethernet---- adapter vEthernet (Virtual Switch -897f61a2cf88f8403d2e1bc946ef76710ac2540882b31b030445781fcf5eca25-------- ------- ---------
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 Connection State Uptime ParentImageName
-specific--- DNS Suffix .----- ------ ---------------
TP4Demo Off 00:00:00 WindowsServerCore
PS C:\> Get-Container
Name Link State Uptime ParentImageName
-local--- IPv6 Address . .----- .------ . . :---------------
TP4Demo fe80Off 00:00:94400 WindowsServerCore
PS C:73e2\> Start-Container -Name TP4Demo
PS C:2d58\> Enter-PSSession -ContainerName TP4Demo -RunAsAdministrator
[TP4Demo]:7c33%26 PS C:\Windows\system32> Install-WindowsFeature web-server
Success Restart Needed IPv4Exit Address.Code . . . . . .Feature .Result
------- .-------------- .--------- . : 172 --------------
True No Success {Common HTTP Features, Default Document, D.16.0.2
[TP4Demo]: PS C:\Windows\system32> Subnetexit
PS MaskC:\> .Stop-Container .-Name .TP4Demo
PS .C:\> .New-ContainerImage .-ContainerName .TP4Demo .-Name .WindowsServerCoreIIS .-Publisher .Demo :-Version 255.240.01.0
Name Default Gateway . . . . . . . . . : 172 Publisher Version IsOSImage
---- --------- ------- ---------
WindowsServerCoreIIS CN=Demo 1.160.0.10 False
PS C:\> Remove-Container -Name TP4Demo -Force
ipconfig (Host): Now I have an IIS container ready that I bind to the "Virtual Switch".
PS C:\Windows\system32> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet0:
\> ConnectionNew-specific DNS Suffix . :
Container Link-local IPv6 Address .Name .IIS .-ContainerImageName .WindowsServerCoreIIS .-SwitchName :"Virtual fe80::19a9:f8bf:6e6d:5544%4Switch"
IPv4 Address. . . . . . . . . . . : 10.10.0.79
Name State SubnetUptime Mask . .ParentImageName
---- .----- .------ . . .---------------
IIS . .Off . . 00:00:00 255.255.254.0WindowsServerCoreIIS
Default Gateway
PS .C:\> .Start-Container .-Name .IIS
PS .C:\> .Invoke-Command .-ContainerName .IIS .{ipconfig}
Windows :IP 10.10.0.1Configuration
Ethernet adapter vEthernet (Virtual Switch-30179F35-A9BD-4231-B264-BDD2994BD956-0):
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::cc1724f4:6b74c726:4fabed9b:ecce%3e603%28
IPv4 Address. . . . . . . . . . . : 172.16.0.12
Subnet Mask . . . . . . . . . . . : 255.240.0.0
Default Gateway . . . . . . . . . :
Tunnel adapter isatap.{0DADB974-F583-4B51-B4B0-C7526A8BABAD}:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Tunnel adapter isatap.{0D2767F2-FF2B-4D79-B338-94722C2CF8F9}:
Media State . . . . . . . . . 172. 16. : Media disconnected
Connection-specific DNS Suffix 0. :1
For testing purposes, I just installed an Apache httpd server on the Windows 2016 host and let it run on port 80, in order to blockAdding port 80 there.
Then I runmapping and firewall rule:
dockerPS runC:\> if (!(Get-NetNatStaticMapping | where {$_.ExternalPort -nameeq iisdemo80})) {Add-itNetNatStaticMapping -pNatName "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 windowsservercoreiis-Action cmdAllow -Enabled True}
to see if it conflicts (which I expected) due to the port 80 already being in use, but it does not!
@harrymc pointed me to a ticket on Docker's github, where I just added a comment:
https://github.com/docker/docker/issues/15740#issuecomment-202094318
and a new github ticket: https://github.com/docker/docker/issues/21558
======= UPDATE (Using powershell instead of Docker) =======
I tried a different approach, using Powershell instead of Docker to manage the Windows Container.
I followed the exact steps as mentioned on https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell#create-iis-container-1- including the networking configuration.
When I run the container, I also can only access the IIS default page via the container IP 172.16.0.2:80, but not via the host IP 172.16.0.1:80 or 10.10.0.79:80.
Here is some information I checked via Powershell about my current host environment:
PS C:> Get-ContainerHost
Name ContainerImageRepositoryLocation
---- --------------------------------
TEST2016 C:\ProgramData\Microsoft\Windows\Hyper-V\Container Image Store
PS C:> Get-VMSwitch
Name SwitchType NetAdapterInterfaceDescription
---- ---------- ------------------------------
Virtual Switch NAT
PS C:> Get-NetNatStaticMapping
StaticMappingID : 17
NatName : ContainerNat
Protocol : TCP
RemoteExternalIPAddressPrefix : 0.0.0.0/0
ExternalIPAddress : 0.0.0.0
ExternalPort : 80
InternalIPAddress : 172.16.0.2
InternalPort : 80
InternalRoutingDomainId : {00000000-0000-0000-0000-000000000000}
Active : True
PS C:\> Get-NetFirewallRule | where {$_.Name -eq "TCP80"}
Name : TCP80
DisplayName : HTTP on TCP/80
Description :
DisplayGroup :
Group :
Enabled : True
Profile : Any
Platform : {}
Direction : Inbound
Action : Allow
EdgeTraversalPolicy : Block
LooseSourceMapping : False
LocalOnlyMapping : False
Owner :
PrimaryStatus : OK
Status : The rule was parsed successfully from the store. (65536)
EnforcementStatus : NotApplicable
PolicyStoreSource : PersistentStore
PolicyStoreSourceType : Local
Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host.
ipconfig on containerBut 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/
[IIS]: PS C:\Windows\system32>\> ipconfig
wget http://10.10.0.79:80/
Windowswget IP: Configuration
Unable to connect to the remote server
EthernetAt adapterline:1 vEthernetchar:1
+ (Virtualwget Switch-05D94B20-1CA5-4198-A3AA-2CA7001925D0-http://10.10.0).79:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
Connection-specific DNS+ SuffixCategoryInfo . :
Link-local IPv6 Address . .: .InvalidOperation: (System. Net. HttpWebRequest:HttpWebRequest) fe80::d89d:bcca:e4fa:35db%26[Invoke-WebRequest], WebException
IPv4 Address.+ .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.21:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
Subnet Mask .+ .CategoryInfo . . . . . . . . . : 255.240.0.0
Default GatewayInvalidOperation: (System. Net.HttpWebRequest:HttpWebRequest) .[Invoke-WebRequest], .WebException
. . . .+ .FullyQualifiedErrorId : 172WebCmdletWebResponseException,Microsoft.16PowerShell.0Commands.1InvokeWebRequestCommand
ipconfig on host:
Ethernet adapter Ethernet0:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::19a9:f8bf:6e6d:5544%4
IPv4 Address. . . . . . . . . . . : 10.10.0.79
Subnet Mask . . . . . . . . . . . : 255.255.254.0
Default Gateway . . . . . . . . . : 10.10.0.1
Ethernet adapter vEthernet (Virtual Switch):
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::cc17:6b74:4fab:ecce%3
IPv4 Address. . . . . . . . . . . : 172.16.0.1
Subnet Mask . . . . . . . . . . . : 255.240.0.0
Default Gateway . . . . . . . . . :
Tunnel adapter isatap.{0DADB974-F583-4B51-B4B0-C7526A8BABAD}:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Tunnel adapter isatap.{0D2767F2-FF2B-4D79-B338-94722C2CF8F9}:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
I can only reach the IIS default page via the container IP (http://172.16.0.2:80).