• Get In Touch
June 11, 2016

Networking with Docker Containers

Need Hosting? Try ours, it's fast, reliable and feature loaded with support you can depend on.
View Plans

As you build your distributed application, the services is composes of will need to be able to communicate with each other. These services, running in the containers, might be on a single host, on multiple hosts or even across data centers – therefore container networking is a critical factor of any Docker-based distributed application.

Networking with docker containers is a very important featured of Docker. The feature allows users to define their own networks and connect containers to them. You can create a network on a single host or a network that spans across multiple hosts using docker network feature.

In this article, we will learn some basic and advanced networking tools that you can use for managing Docker Containers.

Requirements

  • Ubuntu server 14.04 with docker installed on your system
  • A non-root user account with sudo privilege set up on your server

Docker Default Network

Docker creates a pair of virtual Ethernet interfaces on each container, randomly assigning them an IP address and a subnet from a private address range not already used by the host system. When you install docker, it creates three networks automatically.

You can list these networks by simply running the following command:

sudo docker network ls

You should see the following output:

    NETWORK ID          NAME                DRIVER
    869479a5b4ce        bridge              bridge              
    82f7b88ba977        none                null                
    f5c76b57fe4f        host                host                

The bridge network represents the docker0 network present in all Docker installations.
The none network adds a container to a container-specific network stack.
The host network adds a container on the hosts network stack.

Find the Docker Interface

By default docker creates a bridge interface – docker0 on the host system when the docker process starts up. Docker assigns the IP address 172.17.0.2/16 to the bridge interface docker0 which acts as a subnet for all the IP addresses of the running containers.

You can easily find out the docker bridge interface and IP address by running the following command:

sudo ip a

You should see the output like this:

    1: lo:  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: wlan0:  mtu 1500 qdisc mq state UP group default qlen 1000
        link/ether 4c:bb:58:9c:f5:55 brd ff:ff:ff:ff:ff:ff
        inet 192.168.0.105/24 brd 192.168.0.255 scope global wlan0
           valid_lft forever preferred_lft forever
        inet6 fe80::4ebb:58ff:fe9c:f555/64 scope link 
           valid_lft forever preferred_lft forever
    3: docker0:  mtu 1500 qdisc noqueue state DOWN group default 
        link/ether 02:42:25:2f:fd:5d brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.2/16 scope global docker0
           valid_lft forever preferred_lft forever

Basic Container Networking

When docker starts a container, it creates a virtual interface on host system with unique name like vethef766ac, and assign IP address within the same subnet.

This new interface will be connected to the eth0 interface on the container and allow networking between containers by adding iptable rules. A NAT rule is used to forward traffic to external hosts and the host machine must be set up to forward IP packets.

You can see the iptable NAT rules by running the following command on host system:

sudo iptables -t nat -L

The output looks something like this:

    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination         
    DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL

    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination         

    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination         
    DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination         
    MASQUERADE  all  --  172.17.0.0/16        anywhere            

    Chain DOCKER (2 references)
    target     prot opt source               destination         
    RETURN     all  --  anywhere             anywhere            

You should see the POSTROUTING chain in the above output. It has a rule that will masquerade all traffic originating from 172.17.0.0/16 (docker bridge network). This masquerade rule will allow containers to reach the outside world.

Creating Your Own Network Bridge

If you want to assign a custom static IP address to the containers, you will need to create new bridge interface br0 in the host system.

To do this, Run following commands on the host machine running docker.

First stop docker service:

sudo service docker stop

Add br0 interface:

sudo ip link add br0 type bridge

Assign the network range as you wish and up br0 interface:

sudo ip addr add 192.168.1.0/24 dev br0
sudo ip link set br0 up

After creating the docker bridge, you will need to add the following line in /etc/default/docker file:

sudo nano /etc/default/docker

Add the following line at the end of file:

    DOCKER_OPTS="-b=br0"

Save and close the file and start docker service:

sudo service docker start

You should see the new bridge interface br0 by running the following command on host machine:

ifconfig

    br0       Link encap:Ethernet  HWaddr b2:31:08:29:92:3d  
              inet addr:192.168.1.1  Bcast:0.0.0.0  Mask:255.255.255.0
              inet6 addr: fe80::b031:8ff:fe29:923d/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:64 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:0 (0.0 B)  TX bytes:10425 (10.4 KB)

    docker0   Link encap:Ethernet  HWaddr 02:42:25:2f:fd:5d  
              inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
              UP BROADCAST MULTICAST  MTU:1500  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:1941 errors:0 dropped:0 overruns:0 frame:0
              TX packets:1941 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:198438 (198.4 KB)  TX bytes:198438 (198.4 KB)

    wlan0     Link encap:Ethernet  HWaddr 4c:bb:58:9c:f5:55  
              inet addr:192.168.0.105  Bcast:192.168.0.255  Mask:255.255.255.0
              inet6 addr: fe80::4ebb:58ff:fe9c:f555/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:17817 errors:0 dropped:0 overruns:0 frame:0
              TX packets:18678 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:13667483 (13.6 MB)  TX bytes:2759827 (2.7 MB)

In the above output, the bridged interface will range the docker containers with the IP address followed by bridge IP subnet.

Retrieve a Docker container’s IP address

You can use the docker inspect command with “Container ID” to find the IP address of the running container.

To do this, run following command to find detailed information about your docker container including its internal IP address:

sudo docker inspect "container ID"

You should see the following output:

     "NetworkSettings": {
                "Bridge": "",
                "SandboxID": "eecb33f2612bf4ab3f726e51cb3f6abb763194abbf0c2673abb05bf12f1cce55",
                "HairpinMode": false,
                "LinkLocalIPv6Address": "",
                "LinkLocalIPv6PrefixLen": 0,
                "Ports": {},
                "SandboxKey": "/var/run/docker/netns/eecb33f2612b",
                "SecondaryIPAddresses": null,
                "SecondaryIPv6Addresses": null,
                "EndpointID": "d144ed794bec7d603e3c5a89ad05fd2560a3e7c476a5976941d1c4d45e9514a5",
                "Gateway": "192.168.1.1",
                "GlobalIPv6Address": "",
                "GlobalIPv6PrefixLen": 0,
                "IPAddress": "192.168.1.2",
                "IPPrefixLen": 24,
                "IPv6Gateway": "",
                "MacAddress": "02:42:c0:a8:01:02",
                "Networks": {
                    "bridge": {
                        "IPAMConfig": null,
                        "Links": null,
                        "Aliases": null,
                        "NetworkID": "848b570ed482f2dad8b7d95482cb1b6f51700ea3b070059454781326ac6a34d2",
                        "EndpointID": "d144ed794bec7d603e3c5a89ad05fd2560a3e7c476a5976941d1c4d45e9514a5",
                        "Gateway": "192.168.1.1",
                        "IPAddress": "192.168.1.2",
                        "IPPrefixLen": 24,
                        "IPv6Gateway": "",
                        "GlobalIPv6Address": "",
                        "GlobalIPv6PrefixLen": 0,
                        "MacAddress": "02:42:c0:a8:01:02"

If you want to get the container’s IP address value only, run:

sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' "container ID"

You should see the following output:

        192.168.1.2

Depending on the operating system running within your docker container you can also retrieve it’s IP address using ifconfig command:

sudo docker exec -it "container ID" /sbin/ifconfig eth0

The output looks something like this:

    eth0      Link encap:Ethernet  HWaddr 02:42:c0:a8:01:02  
              inet addr:192.168.1.2  Bcast:0.0.0.0  Mask:255.255.255.0
              inet6 addr: fe80::42:c0ff:fea8:102/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:50 errors:0 dropped:0 overruns:0 frame:0
              TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:7803 (7.8 KB)  TX bytes:648 (648.0 B)

Docker Single Host Networking

You can create a new network with docker network create command.
In this example, we’ll create a network called net1 and run an ubuntu container inside it:

sudo docker network create net1

You can list the network by running the following command:

sudo docker network ls

You should see the following output:

    NETWORK ID          NAME                DRIVER
    01fd54caa4cb        bridge              bridge              
    5afe75f128a9        none                null                
    36f9ac8fb08a        host                host                
    cc69e97309e5        net1                bridge              

Now, you can easily run ubuntu container inside net1 network:

sudo docker run -itd --net=net1 ubuntu

You can disconnect and delete docker network any time by running the following command:

sudo docker network disconnect net1
sudo docker network rm net1

Docker Multi Host Networking

In this example, we will create three docker hosts on virtual box using a docker machine. One host runs consul and other two hosts share the network information using the consul service discovery container on the first host.

Before creating a docker machine, you will need to download the docker-machine binary.

To do so, run the following command:

sudo curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-uname -s-uname -m> /usr/local/bin/docker-machine
sudo chmod +x /usr/local/bin/docker-machine

Now, create a docker machine named host1:

sudo docker-machine create -d virtualbox host1

You should see the following output:

    Creating CA: /root/.docker/machine/certs/ca.pem
    Creating client certificate: /root/.docker/machine/certs/cert.pem
    Running pre-create checks...
    (host1) Image cache directory does not exist, creating it at /root/.docker/machine/cache...
    (host1) No default Boot2Docker ISO found locally, downloading the latest release...
    (host1) Latest release for github.com/boot2docker/boot2docker is v1.11.1
    (host1) Downloading /root/.docker/machine/cache/boot2docker.iso from https://github.com/boot2docker/boot2docker/releases/download/v1.11.1/boot2docker.iso...
    (host1) 0%....10%....20%....30%....40%....50%....60%....70%....80%....90%....100%
    Creating machine...
    (host1) Copying /root/.docker/machine/cache/boot2docker.iso to /root/.docker/machine/machines/host1/boot2docker.iso...
    (host1) Creating VirtualBox VM...
    (host1) Creating SSH key...
    (host1) Starting the VM...
    (host1) Check network to re-create if needed...
    (host1) Found a new host-only adapter: "vboxnet0"
    (host1) Waiting for an IP...
    Waiting for machine to be running, this may take a few minutes...
    Detecting operating system of created instance...
    Waiting for SSH to be available...
    Detecting the provisioner...
    Provisioning with boot2docker...
    Copying certs to the local machine directory...
    Copying certs to the remote machine...
    Setting Docker configuration on the remote daemon...
    Checking connection to Docker...
    Docker is up and running!
    To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env host1

You can launch a consul container on the host1 host using the following docker run command.

sudo docker $(docker-machine config host1) run -d -p "8500:8500" -h "consul" progrium/consul -server -bootstrap

You should see the following output:

    Unable to find image 'progrium/consul:latest' locally
    latest: Pulling from progrium/consul
    c862d82a67a2: Pull complete 
    0e7f3c08384e: Pull complete 
    0e221e32327a: Pull complete 
    09a952464e47: Pull complete 
    60a1b927414d: Pull complete 
    4c9f46b5ccce: Pull complete 
    417d86672aa4: Pull complete 
    b0d47ad24447: Pull complete 
    fd5300bd53f0: Pull complete 
    a3ed95caeb02: Pull complete 
    d023b445076e: Pull complete 
    ba8851f89e33: Pull complete 
    5d1cefca2a28: Pull complete 
    Digest: sha256:8cc8023462905929df9a79ff67ee435a36848ce7a10f18d6d0faba9306b97274
    Status: Downloaded newer image for progrium/consul:latest
    55bdd87b9551416b2d02b11452960578f9c9c9bb4d0afb74ec1957ca1d210d2e

You can verify the status of running container using the following command:

sudo docker $(docker-machine config host1) ps

You should see the running container in following output:

    CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS              PORTS                                                                            NAMES
    55bdd87b9551        progrium/consul     "/bin/start -server -"   Less than a second ago   Up 2 minutes        53/tcp, 53/udp, 8300-8302/tcp, 8400/tcp, 8301-8302/udp, 0.0.0.0:8500->8500/tcp   cocky_franklin

Now, launch the second docker machine host with parameters to register it with consul running on the host.

To do so, run the following command:

sudo docker-machine create -d virtualbox --engine-opt="cluster-store=consul://$(docker-machine ip host1):8500" --engine-opt="cluster-advertise=eth1:0" host2

You should see the following output:

    Running pre-create checks...
    Creating machine...
    (host2) Copying /root/.docker/machine/cache/boot2docker.iso to /root/.docker/machine/machines/host2/boot2docker.iso...
    (host2) Creating VirtualBox VM...
    (host2) Creating SSH key...
    (host2) Starting the VM...
    (host2) Check network to re-create if needed...
    (host2) Waiting for an IP...
    Waiting for machine to be running, this may take a few minutes...
    Detecting operating system of created instance...
    Waiting for SSH to be available...
    Detecting the provisioner...
    Provisioning with boot2docker...
    Copying certs to the local machine directory...
    Copying certs to the remote machine...
    Setting Docker configuration on the remote daemon...
    Checking connection to Docker...
    Docker is up and running!
    To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env host2

Next, launch the third docker machine by running the following command:

sudo docker-machine create -d virtualbox --engine-opt="cluster-store=consul://$(docker-machine ip host1):8500" --engine-opt="cluster-advertise=eth1:0" host3

Now the two hosts have the default networks which can be used only for single host communication.

To have a multi-host network you need to create an overlay network on host2. You can do this by running the following command:

sudo docker $(docker-machine config host2) network create -d overlay myapp

Now, if you check the networks on host3, you will be able to see the overlay network we created on host2. Because our two hosts are registered with consul and the network information is shared among all the hosts which are registered with it.

To check the network on host2 and host3, run the following command:

sudo docker $(docker-machine config host2) network ls

The output looks like the following:

    NETWORK ID          NAME                DRIVER
    5740258f612b        myapp               overlay             
    870643d6c7d5        bridge              bridge              
    3766f811e564        none                null                
    6703f168bf19        host                host                

sudo docker $(docker-machine config host3) network ls

The output looks like the following:

    NETWORK ID          NAME                DRIVER
    5740258f612b        myapp               overlay             
    0edc1acf9412        bridge              bridge              
    2c582786337d        none                null                
    44306c99cd11        host                host                

Now, if you launch containers in a different host, you will be able to connect them using the container name. Let test it by launching a Nginx container on host2 and test the connection by downloading the default Nginx page from host3 using a busybox container.

You can lunch a Nginx container on host2 by specifying the network myapp we have created.

sudo docker $(docker-machine config host2) run -itd --name=webfront --net=myapp nginx

You should see the following output:

    Unable to find image 'nginx:latest' locally
    latest: Pulling from library/nginx
    8b87079b7a06: Pull complete 
    a3ed95caeb02: Pull complete 
    31c7abf879e0: Pull complete 
    4ef177b369db: Pull complete 
    Digest: sha256:46a1b05e9ded54272e11b06e13727371a65e2ef8a87f9fb447c64e0607b90340
    Status: Downloaded newer image for nginx:latest
    0367c64912557d6cdc5449fc068fa9696a474cacf70eb7702c005cbdeceec70e

Verify the running container using the following command:

sudo docker $(docker-machine config host2) ps

The output looks like the following:

    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
    0367c6491255        nginx               "nginx -g 'daemon off"   12 minutes ago      Up 15 minutes       80/tcp, 443/tcp     webfront

Now, launch a busybox container on host3 with parameters to download the homepage of nginx running on host2.

sudo docker $(docker-machine config host3) run -it --rm --net=myapp busybox wget -qO- http://webfront

You should see the following output:

    Unable to find image 'busybox:latest' locally
    latest: Pulling from library/busybox
    385e281300cc: Pull complete 
    a3ed95caeb02: Pull complete 
    Digest: sha256:4a887a2326ec9e0fa90cce7b4764b0e627b5d6afcb81a3f73c85dc29cea00048
    Status: Downloaded newer image for busybox:latest



    <title>Welcome to nginx!</title>

        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }



    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>

    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br />
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>




Congratulations! The above command returns an HTML output which means the containers are able to connect to other hosts using the overlay network you have created.

Need Hosting? Try ours, it's fast, reliable and feature loaded with support you can depend on.
View Plans

Share this Article!

Related Posts

Node.js Authentication – A Complete Guide with Passport and JWT

Node.js Authentication – A Complete Guide with Passport and JWT

Truth be told, it’s difficult for a web application that doesn’t have some kind of identification, even if you don’t see it as a security measure in and of itself. The Internet is a kind of lawless land, and even on free services like Google’s, authentication ensures that abuses will be avoided or at least […]

Node.js and MongoDB: How to Connect MongoDB With Node

Node.js and MongoDB: How to Connect MongoDB With Node

MongoDB is a document-oriented NoSQL database, which was born in 2007 in California as a service to be used within a larger project, but which soon became an independent and open-source product. It stores documents in JSON, a format based on JavaScript and simpler than XML, but still with good expressiveness. It is the dominant […]

Using MySQL with Node.js: A Complete Tutorial

Using MySQL with Node.js: A Complete Tutorial

Although data persistence is almost always a fundamental element of applications, Node.js has no native integration with databases. Everything is delegated to third-party libraries to be included manually, in addition to the standard APIs. Although MongoDB and other non-relational databases are the most common choice with Node because if you need to scale an application, […]

Node.Js Vs Django: Which Is the Best for Your Project

Node.Js Vs Django: Which Is the Best for Your Project

Django and NodeJs are two powerful technologies for web development, both have great functionality, versatile applications, and a great user interface. Both are open source and can be used for free. But which one fits your project best? NodeJs is based on JavaScript, while Django is written in Python. These are two equally popular technologies […]

Nodejs Vs PHP:  Which Works Best?

Nodejs Vs PHP: Which Works Best?

Before getting into the “battle” between Node.js and PHP we need to understand why the issue is still ongoing. It all started with the increased demand for smartphone applications, their success forcing developers to adapt to new back-end technologies that could handle a multitude of simultaneous requests. JavaScript has always been identified as a client-side […]