While having the ability to create your own networks is a huge leap forward, it means nothing without a means to connect containers to it. In previous versions of Docker, this was traditionally done during container runtime by passing the --net
flag specifying which network the container should use. While this is certainly still the case, the docker network
subcommand also allows you to connect and disconnect running containers to existing networks.
The docker network
subcommand was introduced in Docker 1.9, so you'll need a Docker host running at least that version. In our examples, we'll be using Docker version 1.12. You'll also want to have a good understanding of your current network layout, so you can follow along as we inspect the current configuration. It is assumed that each Docker host is in its native configuration.
Connecting and disconnecting containers is done via the network connect
and network disconnect
subcommands:
user@docker1:~$ docker network connect --help Usage: docker network connect [OPTIONS] NETWORK CONTAINER Connects a container to a network --alias=[] Add network-scoped alias for the container --help Print usage --ip IP Address --ip6 IPv6 Address --link=[] Add link to another container user@docker1:~$
Let's review what our options are for connecting containers to networks:
Once a network connect
request is sent, Docker handles all the configuration required in order for the container to start using the new interface. Let's take a look at a quick example:
user@docker1:~$ docker run --name web1 -d jonlangemak/web_server_1 e112a2ab8197ec70c5ee49161613f2244f4353359b27643f28a18be47698bf59 user@docker1:~$ user@docker1:~$ docker exec web1 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 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 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever user@docker1:~$
In the above output we started a simple container without specifying any network-related configuration. The result is the container being mapped to the docker0
bridge. Now let's try connecting this container to the network we created in the previous recipe, mynetwork
:
user@docker1:~$ docker network connect mynetwork web1 user@docker1:~$ user@docker1:~$ docker exec web1 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 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 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever 10: eth1@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe12:2/64 scope link valid_lft forever preferred_lft forever user@docker1:~$
As you can see, the container now has an IP interface on the network mynetwork
. If we now once again inspect the network, we should see a container association:
user@docker1:~$ docker network inspect mynetwork [ { "Name": "mynetwork", "Id": "a09b7617c5504d4afd80c26b82587000c64046f1483de604c51fa4ba53463b50", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1/16" } ] }, "Internal": false, "Containers": { "e112a2ab8197ec70c5ee49161613f2244f4353359b27643f28a18be47698bf59": { "Name": "web1", "EndpointID": "678b07162dc958599bf7d463da81a4c031229028ebcecb1af37ee7d448b54e3d", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] user@docker1:~$
Networks can be disconnected just as easily. For instance, we can now remove the container from the docker0
bridge by removing it from the bridge network:
user@docker1:~$ docker network disconnect bridge web1 user@docker1:~$ user@docker1:~$ docker exec web1 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 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 10: eth1@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe12:2/64 scope link valid_lft forever preferred_lft forever user@docker1:~$
It's interesting to point out that Docker also takes care of ensuring container connectivity when you connect and disconnect networks from the containers. For instance, before disconnecting the container from the bridge network, the default Gateway of the container was still out of the docker0
bridge:
user@docker1:~$ docker exec web1 ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth2 proto kernel scope link src 172.17.0.2
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.2
user@docker1:~$
This makes sense as we wouldn't want to interrupt container connectivity while connecting the container to a new network. However, once we remove the network hosting the default gateway by disconnecting the interface to the bridge network, we see that Docker updates the default gateway to the remaining interface out of the mynetwork
bridge:
user@docker1:~$ docker exec web1 ip route
default via 172.18.0.1 dev eth1
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.2
user@docker1:~$
This ensures that the container has connectivity regardless of which network it's connected to.
Finally, I want to point out an interesting aspect of the none
network type when you are connecting and disconnecting containers to networks. As I mentioned earlier, the none
network type tells Docker to not assign the container to any networks. This however, does not mean just initially, it's a configuration state telling Docker that the container should not have any networks associated with it. For instance, assume we start the following container with a network of none
:
user@docker1:~$ docker run --net=none --name web1 -d jonlangemak/web_server_1 9f5d73c55ee859335cd2449b058b68354f5b71cf37e57b72f5c984afcafb4b21 user@docker1:~$ docker exec web1 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 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 user@docker1:~$
As you can see, the container doesn't have any network interfaces besides its loopback. Now, let's try and connect this container to a new network:
user@docker1:~$ docker network connect mynetwork web1 Error response from daemon: Container cannot be connected to multiple networks with one of the networks in private (none) mode user@docker1:~$
Docker is telling us that this container was defined to have no networks and is preventing us from connecting the container to any network. If we inspect the none
network, we can see that this container is in fact attached to it:
user@docker1:~$ docker network inspect none [ { "Name": "none", "Id": "a191c26b7dad643ca77fe6548c2480b1644a86dcc95cde0c09c6033d4eaff7f2", "Scope": "local", "Driver": "null", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [] }, "Internal": false, "Containers": { "931a0d7ad9244c135a19de6e23de314698112ccd00bc3856f4fab9b8cb241e60": { "Name": "web1", "EndpointID": "6a046449576e0e0a1e8fd828daa7028bacba8de335954bff2c6b21e01c78baf8", "MacAddress": "", "IPv4Address": "", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] user@docker1:~$
In order to connect this container to a new network, we first have to disconnect it from the none
network:
user@docker1:~$ docker network disconnect none web1 user@docker1:~$ docker network connect mynetwork web1 user@docker1:~$ docker exec web1 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 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 18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe12:2/64 scope link valid_lft forever preferred_lft forever user@docker1:~$
Once you disconnect it from the none
network, you are free to connect it to any other defined network.