Instructor Demo: Single Host Networks

In this demo, we'll illustrate:

  • The networking stack created for the default Docker nat network
  • Attaching containers to docker networks
  • Inspecting networking metadata
  • How network adapters appear in different network namespaces

Following Default Docker Networking

  1. On a fresh node you haven't run any containers on yet, list your networks:

    PS: node-1 Administrator> docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    03f6ddacab50        nat                 nat                 local
    b0de36ba94f3        none                null                local
    
  2. Get some metadata about the nat network, which is the default network containers attach to when doing docker container run:

    PS: node-1 Administrator> docker network inspect nat
    

    Notice the IPAM section:

    "IPAM": {
        "Driver": "windows",
        "Options": null,
        "Config": [
            {
                "Subnet": "172.20.128.0/20",
                "Gateway": "172.20.128.1"
            }
        ]
    }
    

    Docker's IP address management driver assigns a subnet (172.20.128.0/20 in this case) to each nat network, and uses the first IP in that range as the network's gateway.

    Also note the containers key:

    "Containers": {}
    

    So far, no containers have been plugged into this network.

  3. The nat Docker network is composed of a hyper-v virtual switch, and network address translation provided by WinNAT. List your virtual switches:

    PS: node-1 Administrator> Get-VMSwitch
    
    Name SwitchType NetAdapterInterfaceDescription
    ---- ---------- ------------------------------
    nat  Internal
    

    The Internal type indicates that this switch isn't directly connected to a network adapter on the host. Get some metadata about your host's NAT service:

    PS node-1> Get-NetNat
    
    Name                             : H3acfc61d-0d8e-438c-8857-9c2b742707bf
    ExternalIPInterfaceAddressPrefix :
    InternalIPInterfaceAddressPrefix : 172.20.128.1/20
    IcmpQueryTimeout                 : 30
    TcpEstablishedConnectionTimeout  : 1800
    TcpTransientConnectionTimeout    : 120
    TcpFilteringBehavior             : AddressDependentFiltering
    UdpFilteringBehavior             : AddressDependentFiltering
    UdpIdleSessionTimeout            : 120
    UdpInboundRefresh                : False
    Store                            : Local
    Active                           : True
    

    Notice this IP listed here matches the gateway presented by docker network inspect nat.

  4. Next, have a look at what network adapters are present in the host's network namespace:

    PS: node-1 Administrator> ipconfig /all
    
    Windows IP Configuration
    
       Host Name . . . . . . . . . . . . : node-0
       Primary Dns Suffix  . . . . . . . :
       Node Type . . . . . . . . . . . . : Hybrid
       IP Routing Enabled. . . . . . . . : No
       WINS Proxy Enabled. . . . . . . . : No
       DNS Suffix Search List. . . . . . : us-east-1.ec2-utilities.amazonaws.com
                                           ec2.internal
    
    Ethernet adapter vEthernet (HNS Internal NIC):
    
       Connection-specific DNS Suffix  . :
       Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter
       Physical Address. . . . . . . . . : 00-15-5D-E6-0A-79
       DHCP Enabled. . . . . . . . . . . : Yes
       Autoconfiguration Enabled . . . . : Yes
       Link-local IPv6 Address . . . . . : fe80::1074:1c58:105c:eca4%8(Preferred)
       IPv4 Address. . . . . . . . . . . : 172.20.128.1(Preferred)
       Subnet Mask . . . . . . . . . . . : 255.255.240.0
       Default Gateway . . . . . . . . . :
       DHCPv6 IAID . . . . . . . . . . . : 184554845
       DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-22-DF-49-F3-0E-85-CC-1B-93-E6
       DNS Servers . . . . . . . . . . . : fec0:0:0:ffff::1%1
                                           fec0:0:0:ffff::2%1
                                           fec0:0:0:ffff::3%1
       NetBIOS over Tcpip. . . . . . . . : Enabled
    ...
    

    The Host Network Service (HNS) set up the virtual NIC (second block above) corresponding to your virtual switch and NAT when the Docker engine first started on this host.

  5. Create a container attached to your nat network:

    PS: node-1 Administrator> docker container run --name=c1 -dt microsoft/nanoserver
    
  6. Have a look at the network adapters created inside this container's network namespace:

    PS: node-1 Administrator> docker container exec c1 ipconfig /all
    
    Windows IP Configuration
    
       Host Name . . . . . . . . . . . . : 42651ff618f8
       Primary Dns Suffix  . . . . . . . :
       Node Type . . . . . . . . . . . . : Hybrid
       IP Routing Enabled. . . . . . . . : No
       WINS Proxy Enabled. . . . . . . . : No
       DNS Suffix Search List. . . . . . : ec2.internal
    
    Ethernet adapter vEthernet (Container NIC c6951378):
    
       Connection-specific DNS Suffix  . : ec2.internal
       Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter #2
       Physical Address. . . . . . . . . : 00-15-5D-E6-06-12
       DHCP Enabled. . . . . . . . . . . : No
       Autoconfiguration Enabled . . . . : Yes
       Link-local IPv6 Address . . . . . : fe80::50cc:78ae:aa3b:51fd%18(Preferred)
       IPv4 Address. . . . . . . . . . . : 172.20.136.208(Preferred)
       Subnet Mask . . . . . . . . . . . : 255.255.240.0
       Default Gateway . . . . . . . . . : 172.20.128.1
       DNS Servers . . . . . . . . . . . : 172.20.128.1
                                           10.10.0.2
       NetBIOS over Tcpip. . . . . . . . : Disabled
    

    The Host Network Service creates and places a virtual NIC inside the container's network namespace upon container creation, assigning that container an IP address from the nat network's subnet.

  7. Create another container, and ping one from the other by container name:

    PS: node-1 Administrator> docker container run --name=c2 -dt microsoft/nanoserver
    PS: node-1 Administrator> docker container exec c1 ping c2
    
    Pinging c2 [172.20.134.196] with 32 bytes of data:
    Reply from 172.20.134.196: bytes=32 time<1ms TTL=128
    Reply from 172.20.134.196: bytes=32 time<1ms TTL=128
    Reply from 172.20.134.196: bytes=32 time<1ms TTL=128
    Reply from 172.20.134.196: bytes=32 time<1ms TTL=128
    
    Ping statistics for 172.20.134.196:
        Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
        Minimum = 0ms, Maximum = 0ms, Average = 0ms
    

    The ping is successful; Docker uses DNS resolution so that our application logic (ping c2 in this case) doesn't need to do any explicit service discovery or networking lookups by hand; all that is provided by the Docker engine and Windows networking stack.

  8. Create one final container, but don't name it this time, and attempt to ping it from c1 like above:

    PS: node-1 Administrator> docker container run -dt microsoft/nanoserver
    PS: node-1 Administrator> docker container exec c1 ping <new container name>
    
    Ping request could not find host <new container name>. Please check the name and try again.
    

    Docker only provides DNS lookup for containers explicitly named with the --name flag.

Forwarding a Host Port to a Container

  1. Start an iis container with a port exposure:

    PS: node-1 Administrator> docker container run -d -p 5000:80 --name iis microsoft/iis
    

    This syntax asks docker to forward all traffic arriving on port 5000 of the host's network namespace to port 80 of the container's network namespace. Visit the iis landing page at <node-1 public IP>:5000.

  2. List the NAT rules on your host:

    PS: node-1 Administrator> Get-NetNatStaticMapping
    
    StaticMappingID               : 0
    NatName                       : H3acfc61d-0d8e-438c-8857-9c2b742707bf
    Protocol                      : TCP
    RemoteExternalIPAddressPrefix : 0.0.0.0/0
    ExternalIPAddress             : 0.0.0.0
    ExternalPort                  : 5000
    InternalIPAddress             : 172.20.142.213
    InternalPort                  : 80
    InternalRoutingDomainId       : {00000000-0000-0000-0000-000000000000}
    Active                        : True
    

    There should be one similar to the above, with ExternalPort: 5000, InternalPort: 80 and InternalIPAddress matching the IP of your iis container (try docker container inspect <iis container ID> or docker network inspect nat to see that this IP corresponds to your iis container).

  3. Delete all you containers on this node to clean up:

    PS: node-1 Administrator> docker container rm -f $(docker container ls -aq)
    

Conclusion

In this demo, we stepped through the basic behavior of docker software defined nat networks, and looked at the technology underpinning them such as virtual switches and virtual NICs. By default, all containers started on a host without any explicit networking configuration will be able to communicate across Docker's nat network, and in order for containers to resolve each other's name by DNS, they must also be explicitly named upon creation.