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.