Docker Networking: bridge, host and none networks

Networking in Docker

In the previous post, we touched on networking just a bit when I mentioned bridged networks. Networking with Docker can get as intricate as networking anywhere else. So I am not going to be covering everything there is to know in this post. However, in this post I will cover some of the basics that will help get you started.

For the demo, we’re going to use an image that’s based on Ubuntu 16. 04 and then add some networking tools on top to help kind of show the networking concepts just a bit. Here’s a look at the file.

FROM ubuntu:16.04

RUN apt update && apt install -y \
    arp-scan \
    iputils-ping \
    iproute2

COPY webapp /

CMD ["/bin/bash"]

# This container is used for demonstating networking in docker
# arp-scan --interface=eth0 --localhost

It starts with the FROM instruction, specifying that the base image is Ubuntu, and then it specifies the tag of 16.04. The next instruction is the RUN instruction, which is used to install some packages with the Apt package manager. These packages contain some networking binaries, things such as ping, arp-scan, IP, and others. The COPY instruction, we’re using that to copy the same web application binary that we used previously. And then finally, the CMD sets the default command to run bash. So this image will have the tools needed to test out networking with Docker.

docker networks

The docker network command along with the ls sub-command can be used to shown existing networks.

(base) shravan-network-example# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3011d8e256e1        bridge              bridge              local
c634d8b80316        host                host                local
5432078a894f        none                null                local
(base) shravan-network-example#

The three that are listed here are the three that are pre-configured by Docker. The info in this table is pretty basic. There’s an ID, a name, a driver, and a scope. All of these have a local scope, which means they all exist as networks only on this local host. We’re only going to cover these three local options in this post.

Let’s go through these three types. The bridge network is the default. Whenever you start up a new container and you don’t specify a network, it’s going to use the default bridge network.

build the image

So let’s build the image from the Dockerfile shown above and call it ubuntu_networking.

(base) shravan-network-example# docker build -t "ubuntu_networking" .
Sending build context to Docker daemon  6.637MB
Step 1/4 : FROM ubuntu:16.04
16.04: Pulling from library/ubuntu
fe703b657a32: Pull complete
f9df1fafd224: Pull complete
a645a4b887f9: Pull complete
57db7fe0b522: Pull complete
Digest: sha256:e9938f45e51d9ff46e2b05a62e0546d0f07489b7f22fbc5288defe760599e38a
Status: Downloaded newer image for ubuntu:16.04
 ---> 77be327e4b63
Step 2/4 : RUN apt update && apt install -y     arp-scan     iputils-ping     iproute2
 ---> Running in 2f6acb835c95
.....
.....
Removing intermediate container 2f6acb835c95
 ---> bc0c6085b9ef
Step 3/4 : COPY webapp /
 ---> dba2f63323a5
Step 4/4 : CMD ["/bin/bash"]
 ---> Running in e461918afd9e
Removing intermediate container e461918afd9e
 ---> 26d8389f0e30
Successfully built 26d8389f0e30
Successfully tagged ubuntu_networking:latest

Now, lets just check the images

(base) shravan-network-example# docker images
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
ubuntu_networking                 latest              26d8389f0e30        2 minutes ago       214MB
webapp                            latest              6ab358b2f0f6        3 hours ago         6.63MB
ubuntu_python                     latest              1ede71222aef        5 hours ago         128MB
greeting                          latest              b5ab325138b1        24 hours ago        1.88MB

Bridge network

Now, we can start a container based off of this image. docker run -it ubuntu_networking. Let’s start off by listing the interfaces for this container.

(base) shravan-network-example# docker run -it ubuntu_networking
root@c61657c10d77:/# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd ::
50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
root@c61657c10d77:/#

And there we have the loopback interface, and we have the eth0 with an address of 172.17.0.2. This container is using the bridge driver (see above), which is connected to the interfaces on the host. So that means this has full connectivity. If I ping google.com, we have some results that come back.

oot@c61657c10d77:/# ping google.com
PING google.com (172.217.12.174) 56(84) bytes of data.
64 bytes from lga25s62-in-f14.1e100.net (172.217.12.174): icmp_seq=1 ttl=37 time=6.79 ms
64 bytes from lga25s62-in-f14.1e100.net (172.217.12.174): icmp_seq=2 ttl=37 time=11.7 ms
64 bytes from lga25s62-in-f14.1e100.net (172.217.12.174): icmp_seq=7 ttl=37 time=13.0 ms
^C
--- google.com ping statistics ---
7 packets transmitted, 7 received, 0% packet loss, time 6017ms
rtt min/avg/max/mdev = 5.965/11.003/13.648/2.980 ms
root@c61657c10d77:/#

Okay, I want to detach from this container without stopping it. You can do this by typing ctrl + p followed by ctrl + q.

root@c61657c10d77:/# (base) shravan-network-example# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
c61657c10d77        ubuntu_networking   "/bin/bash"         6 minutes ago       Up 6 minutes                            practical_heisenberg
(base) shravan-network-example#

From here on the host, you can interact with the container via its IP address. So if I ping it, technically this should work, but on mac with docker for desktop, it doesn’t. Its a long story, you can read about it. For now, I will spin up another container to demonstrate networking concept.

Here, I started another container, and as you can see, it has an IP address of 172.17.0.3.

(base) shravan-network-example# docker run -it ubuntu_networking
root@37d3d3b1069a:/# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd ::
52: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
root@37d3d3b1069a:/#

So now we have two containers running inside of the network. Let’s start up one more and ping the other two containers on the network.

(base) shravan-network-example# docker run -it ubuntu_networking

root@4204ffa1e486:/# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.122 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.180 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.179 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.168 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.129 ms
^C
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4100ms
rtt min/avg/max/mdev = 0.122/0.155/0.180/0.028 ms

root@4204ffa1e486:/# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.112 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.175 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.203 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.183 ms
64 bytes from 172.17.0.3: icmp_seq=5 ttl=64 time=0.124 ms
^C
--- 172.17.0.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4114ms
rtt min/avg/max/mdev = 0.112/0.159/0.203/0.036 ms
root@4204ffa1e486:/#

Next, I want to show all of the containers on this network, so for that I’m going to use the arp-scan tool. arp-scan --interface=eth0 --localnet

root@4204ffa1e486:/# arp-scan --interface=eth0 --localnet
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.8.1 with 65536 hosts (http://www.nta-monitor.com/tools/arp-scan/)
172.17.0.1	02:42:d7:3e:dc:c9	(Unknown)
172.17.0.2	02:42:ac:11:00:02	(Unknown)
172.17.0.3	02:42:ac:11:00:03	(Unknown)

Okay, take a look at the results. We have the default gateway at the IP address ending in one. Then the other two are the two containers that I started before this one. So all of these containers that I started up are in this bridge network.

They have access to interact with each other as well as being able to reach the outside world. Now there’s not much you can do to customize the default network. However, you can create your own networks if you need some sort of customization. All right, let’s check out the next network on the list, which is our host network.

Host Network

The host network is an interesting one. Host networks add the container to the host’s networking. This means if you have an application inside of the container running on, say, port 8080, it’s going to be bound to port 8080 on the host.

A host network has no isolation between the host and the containers.

Let’s test this out by running the web application, which binds to port 8080. Because this isn’t the default network, we need to specify the host network in the command prompt here using the network flag. So this command will run the container in the background using the host network, and it’s going to run that web application.

(base) shravan-network-example# docker run -d --network=host ubuntu_networking /webapp
4e07015c86527805bb4e239e5113417b86c7cf0c203f601979c68bcfac03b1a2
(base) shravan-network-example# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
4e07015c8652        ubuntu_networking   "/webapp"           18 seconds ago      Up 17 seconds                           condescending_dubinsky
4204ffa1e486        ubuntu_networking   "/bin/bash"         3 hours ago         Up 3 hours                              exciting_ritchie
37d3d3b1069a        ubuntu_networking   "/bin/bash"         3 hours ago         Up 3 hours                              vigilant_burnell
c61657c10d77        ubuntu_networking   "/bin/bash"         3 hours ago         Up 3 hours                              practical_heisenberg
(base) shravan-network-example#

Now listing off the containers, you can see that it’s running, and if we inspect the container, you’ll see that it doesn’t get its own IP address. Check out here under the networks section, the IP Address property is empty, and that’s because everything is exposed on this current host.

"NetworkSettings": {
            "Bridge": "",
            "SandboxID": "4724b5c0334b052890c91b07209dec8dd2efe05d4ac627251746e99ae00c6401",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/default",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "host": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "c634d8b80316f514fe69d4f1d05c00038cedc4ddbcb829c181717d60be9b3dc0",
                    "EndpointID": "962e35c476c9eaf5aa4a83c69779e7fc27d9f1644c87f5028bb53ac5b38fd506",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": null
                }

Now, if you access http://localhost:8080/shravan you should be able to do that without doing any port mappings. Now recall that in the Dockerfile, we didn’t actually expose port 8080, and we didn’t publish any of those ports manually. When using host networking, whatever ports you open up in the container are going to be bound to the host.

None network

This, as the name suggests, means there’s no network at all. Let’s start up a container using the none network.

(base) shravan-network-example# docker run -it --network=none ubuntu_networking
root@247d923a23e0:/# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd ::
root@247d923a23e0:/# ping google.com
ping: unknown host google.com
root@247d923a23e0:/#

Okay, so here we’re at our bash prompt. If I list off the network interfaces, you can see that there’s only the loopback interface. And if I try and ping google.com, it’s going to fail. And there it is.

It’s failed. So the none network is just what it says. There’s no networking interface. It’s completely isolated.

Tags:

Updated: