Docker networking IPv6 exposed

dockerdocker-machineipv6netstatport-forwarding

I'm running a small arm board providing some services within our local network. As I try to understand the ipv6 support of docker, I am quite confused about the results of my first tests.

My network is controlled by a single route using dhcpv6, every client has 2 valid global ipv6 addresses (also 1 local ipv4) and is protected by the firewall of the router (not allowing requests from the internet to the clients).

The arm board is running ubuntu 16.04, has a valid ipv6 address with privacy extensions enabled.

All docker containers are using the default bridge network without any adjustments.

On the docker host

netstat -tulpen|grep docker

shows

tcp6       0      0 :::8080                 :::*                    LISTEN      0          22490       1559/docker-proxy

Not a single ipv4 service listening.

Inside this docker container same netstat request gives

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          23955       8/nginx         
tcp6       0      0 :::80                   :::*                    LISTEN      0          23956       8/nginx  

Nginx is listening on ipv6 as well as ipv4 – the port 80 is exposed to port 8080 with

docker run (...) -p 8080:80 (...) 

Inspecting the bridge network

docker network inspect bridge

shows the default local bridge

(...)
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
(...)

"b10cf3750252daf0ba11a59cfcd64c72194adcaacd4b9b5df17fae0f53fc4f00": {
                "Name": "ng",
                "EndpointID": "f42de3590072dec2b0d3fae61fc89aeffcb8e6e716b27f5736272fcc8f94f643",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
(...)

Now to my question:

As I understand the configuration the docker bridge ipv6 is disabled, the docker container doesn't have a ipv6 – ipv4 only. Nginx listens on ipv4 as well as ipv6 – ignoring the fact that there is no ipv6 available.

Why is the nginx service on the host exposed on port 8080 only listed as available via ipv6?

Validating this using another network client with

curl -g -6 http://[DOCKER_HOST_IPV6]:8080
curl http://[DOCKER_HOST_IPV4]:8080

shows the service is available with ipv6 as well as ipv4 – why does netstat not show the service as ipv4 service?

If ipv6 is disable in the bridge network config, how is the service reachable at all?

I have another container running openvpn on udp 1194. I configured the server to use udp6, validated with netstat inside the container. This container is exposed the same way using the -p flag but is not available at all on the host. How do I bridge this service correctly?

Best Answer

This is not the nginx container that listens ipv6 (btw, the tcp6 socket you see in the container is bound on its fe80:: and ::1, and it is not reachable from outside the container world). This is the docker-proxy process that manages the host port. When you use "-p 8080:80", docker-proxy bind a tcp6 socket on the host ::0 listening on port 8080 (and tcp6 sockets accept tcp4 also).

So a disabled ipv6 support on docker (default) means your containers only have ipv4 assigned, but docker-proxy "translate" v6 to v4 :

(ipv6 world) -> docker host ipv6:8080 -> [docker-proxy] -> nginx container ipv4:80