Tag Archives: Docker

Docker, IPv6 and –net=”host”

As you recall from the last few blog posts, I went through basic IPv6 deployment for Docker Engine, Docker HubDocker Registry and Docker Swarm.  All of those configurations were using default Docker networking using the Docker-provided bridge layout.

Over the past few months, I have met with several customers who don’t use the Docker bridge setup at all. They use the Docker run option of –net=”host” to do what they call “native” networking.  Simply put, this flag has containers run using the networking configuration of the underlying Linux host.  The advantage of this is that it is brain-dead simple to understand, troubleshoot and use.  The one drawback to this setup is that you can very easily have port conflicts.  Meaning that if I run a container on port 80 which is listening natively on the Linux host and I run another container that needs that same port number then there is a conflict because only one listener can be active for that port at a time.

All of the customers I have met with have no need to run  containers on the same host that use the exact same port so this is a magical option for them.

IPv6 works just as it should in this networking scenario.  Let’s take a look at an example setup.

In the ‘ip a’ output below, you can see that ‘docker-v6-1’ has IPv6 addressing on the eth0 interface (See the Docker Engine post on enabling IPv6):

root@docker-v6-1:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:f3:f8:48 brd ff:ff:ff:ff:ff:ff
    inet 192.168.80.200/24 brd 192.168.80.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fd15:4ba5:5a2b:1009:e91e:221:a4a0:2223/64 scope global temporary dynamic
       valid_lft 83957sec preferred_lft 11957sec
    inet6 fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848/64 scope global dynamic
       valid_lft 83957sec preferred_lft 11957sec
    inet6 fe80::20c:29ff:fef3:f848/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:f3:f8:52 brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:93:33:cc:66 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fd15:4ba5:5a2b:100a::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::42:93ff:fe33:cc66/64 scope link
       valid_lft forever preferred_lft forever
    inet6 fe80::1/64 scope link
       valid_lft forever preferred_lft forever

As a test, I will run a NGINX container using the –net=”host” option. Before I run the container, I disable the “ipv6only” functionality in the NGINX default.conf file so that I have dual stack support.

Create/edit a NGINX default.conf file with the following setting changed:

listen       [::]:80 ipv6only=off;

Now, run the container with the –net-“host” option set and bind mount a volume to where that default.conf file is located on the Docker host:

root@docker-v6-1:~# docker run -itd --net="host" -v ~/default.conf:/etc/nginx/conf.d/default.conf nginx

Using the –net=”host”, the new container will use the same IPv4 and IPv6 address of the host and listen on port 80 (the default in the NGINX setup):

root@docker-v6-1:~# netstat -nlp | grep nginx
tcp6       0      0 :::80                   :::*                    LISTEN      2554/nginx: master

Test accessing the NGINX default page over IPv4 using the 192.168.80.200 address (reference eth0 above):

root@docker-v6-1:~# wget -O - http://192.168.80.200
--2016-04-21 11:00:50--  http://192.168.80.200/
Connecting to 192.168.80.200:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 612 
Saving to: ‘STDOUT’

 0% [                                                                                                 ] 0           --.-K/s              

Welcome to nginx!

.....[output truncated for clarity]

Test accessing the NGINX default page over IPv6 using the fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848 address (Reference eth0 above)”

root@docker-v6-1:~# wget -O - http://[fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848]
--2016-04-21 11:01:13--  http://[fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848]/
Connecting to [fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 612 
Saving to: ‘STDOUT’

 0% [                                                                                                 ] 0           --.-K/s              

Welcome to nginx!

.....[output truncated for clarity]

It works!

Remember that this is cool and all but watch out for port conflicts between containers.  Shown below is an example of what you will see if you run two containers on the same host with –net=”host” set and both use the same port.  You will see one or more of the containers exit and likely pop-up a message in the log that looks like this:

root@docker-v6-1:~# docker logs b47aa56cc822
2016/06/17 17:49:34 [emerg] 1#1: bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

Docker Registry with IPv6

If you have been following along, you know that I started a series of posts aimed at identifying IPv6 support for the various Docker components/services.

The first blog post was focused on Docker Engine, which has pretty reasonable support for basic IPv6.

The second blog post was focused on Docker Hub, which has zero IPv6 support. This is due to it being hosted on AWS and no IPv6-enabled front-end is deployed.

This blog post will focus on Docker Registry.

As I stated in the past two blog entries, I am not here to teach you Docker (what it is, how to deploy it, etc..). I am simply showing basic functionality of various Docker components/services when used with IPv6.

For information on setting up your own Docker Registry, check out:

https://docs.docker.com/registry/

I am using Docker version 1.8.3, Docker Compose version 1.4.2 and Docker Registry version 2.

I am using the same Ubuntu 14.04.3 hosts that I have used in the last two blog posts.

My setup uses two hosts with the following configuration:

  • docker-v6-1:
    • Role: Docker Registry
    • IPv6 Address: fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848/64
  • docker-v6-2:
    • Role: Docker Host/Client
    • IPv6 Address: fd15:4ba5:5a2b:1009:20c:29ff:febb:cbf8/64

My Docker Registry (running on ‘docker-v6-1’) uses self-signed cert and is started using either the ‘docker run’ syntax or Docker Compose. I show both examples below:

docker run:

docker run -d -p 5000:5000 --restart=always --name registry \
  -v `pwd`/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2

Use Docker Compose to run Docker Registry
I am using a file named “docker-compose.yml” to launch my registry.

registry:
  restart: always
  image: registry:2
  ports:
    - 5000:5000
  environment:
    REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
    REGISTRY_HTTP_TLS_KEY: /certs/domain.key
  volumes:
    - /certs:/certs

Run Docker Compose:

docker-compose up -d

Verify Connectivity
On the Docker host/client (“docker-v6-2”),  verify that the Docker Registry host (“docker-v6-1”) can be reached over IPv6:

root@docker-v6-2:~# ping6 -n docker-v6-1.example.com
PING docker-v6-1.example.com(fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848) 56 data bytes
64 bytes from fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848: icmp_seq=1 ttl=64 time=0.402 ms
64 bytes from fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848: icmp_seq=2 ttl=64 time=0.367 ms

Docker Registry Push/Pull Verification
Now that connectivity to the Docker Registry host is working, tag a local Docker image and then push it (over IPv6) to the Docker Registry:

root@docker-v6-2:~# docker tag ubuntu docker-v6-1.example.com:5000/ubuntu

root@docker-v6-2:~# docker push docker-v6-1.example.com:5000/ubuntu
The push refers to a repository [docker-v6-1.example.com:5000/ubuntu] (len: 1)
a005e6b7dd01: Image successfully pushed
002fa881df8a: Image successfully pushed
66395c31eb82: Image successfully pushed
0105f98ced6d: Image successfully pushed
latest: digest: sha256:167f1c34ead8f1779db7827a55de0d517b7f0e015d8f08cf032c7e5cd6979a84 size: 6800

A tcpdump on the Docker Registry shows traffic between docker-v6-1 and docker-v6-2 for the ‘push’ using the previously defined port 5000:

root@docker-v6-1:~# tcpdump -n -vvv ip6 -i eth0
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
19:36:09.283820 IP6 (hlim 64, next-header TCP (6) payload length: 40) fd15:4ba5:5a2b:1009:20c:29ff:febb:cbf8.56066 > fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848.5000: Flags [S], cksum 0x65b1 (correct), seq 2754754540, win 28800, options [mss 1440,sackOK,TS val 645579 ecr 0,nop,wscale 7], length 0
19:36:09.283930 IP6 (hlim 64, next-header TCP (6) payload length: 40) fd15:4ba5:5a2b:1009:20c:29ff:fef3:f848.5000 > fd15:4ba5:5a2b:1009:6540:bb36:2e23:f5a2.56066: Flags [S.], cksum 0xcd92 (incorrect -> 0x50bd), seq 1577491031, ack 2754754541, win 28560, options [mss 1440,sackOK,TS val 859496 ecr 645579,nop,wscale 7], length 0

It works!

Happy Dockering,

Shannon

Docker Hub – We don’t need no stinking IPv6!

I got a lot of great feedback on my last post about the basic configuration of Docker Engine with IPv6.  The next topic that I wanted to cover (and was excited to test) was Docker Hub with IPv6.

My hopes and dreams were smashed in about 15 seconds when I found out that IPv6 is not enabled for hub.docker.com and none of my docker login, docker search, docker pull, docker push or even a browser session to https://hub.docker.com would work over IPv6.

An nslookup reveals no IPv6. Nada. Zip. :

> hub.docker.com
Server:	208.67.222.222
Address:	208.67.222.222#53

Non-authoritative answer:
hub.docker.com	canonical name = elb-default.us-east-1.aws.dckr.io.

Authoritative answers can be found from:
> docker.com
Server:	208.67.222.222
Address:	208.67.222.222#53

Non-authoritative answer:
docker.com	nameserver = ns-1289.awsdns-33.org.
docker.com	nameserver = ns-1981.awsdns-55.co.uk.
docker.com	nameserver = ns-207.awsdns-25.com.
docker.com	nameserver = ns-568.awsdns-07.net.
docker.com
origin = ns-207.awsdns-25.com
mail addr = awsdns-hostmaster.amazon.com
serial = 1
refresh = 7200
retry = 900
expire = 1209600
minimum = 86400

Insert your favorite sad panda image here. 🙁

I know the Docker folks are in a bind with this since they are using Amazon who is likely the last cloud provider on earth who does not have real IPv6 support (none in EC2-VPC but you can in EC2-Classic).

I will move on from Docker Hub and start checking out other Docker stuff like Registry, Compose, etc…

See you next time. Sorry for the epic failure of this post.

Shannon