Weave is an interesting example showcasing the different ways in which a third-party solution can interact with Docker. It offers several different approaches to interacting with Docker. The first is the Weave CLI from which you can not only configure Weave, but also spawn containers much like you would through the Docker CLI. The second is the network plugin, which ties directly into Docker and allows you to provision containers from Docker onto the Weave network. In this recipe, we'll walk through how to connect containers to the Weave network using the Weave CLI. The Weave network plugin will be covered in its own recipe later in this chapter.
It is assumed that you're building off of the lab we created in the first recipe of this chapter. It is also assumed that the hosts have Docker and Weave installed. The Weave peering we defined in the previous chapter is also assumed to be in place.
When using the Weave CLI to manage container connectivity, there are two approaches you can take to connect a container to the Weave network.
The first is to use the weave
command to run a container. Weave accomplishes this by passing anything you specify after weave run
to docker run
. The advantage to this approach is that Weave is made aware of the connection since it's the one actually telling Docker to run the container.
This puts Weave in a perfect position to ensure that the container is started with the proper configuration for it to work on the Weave network. For instance, we can start a container named web1
on the host docker1
using this syntax:
user@docker1:~$ weave run -dP --name=web1 jonlangemak/web_server_1
Note that the syntax for the run
command is identical to that of Docker.
Once the container is started in this manner, let's look at the container's interface configuration:
user@docker1:~$ docker exec web1 ip addr …<Loopback interface removed for brevity>… 20: eth0@if21: <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 22: ethwe@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP link/ether a6:f2:d0:36:6f:bd brd ff:ff:ff:ff:ff:ff inet 10.32.0.1/12 scope global ethwe valid_lft forever preferred_lft forever inet6 fe80::a4f2:d0ff:fe36:6fbd/64 scope link valid_lft forever preferred_lft forever user@docker1:~$
Note that the container now has an additional interface named ethwe
, which has an IP address of 10.32.0.1/12
. This is the Weave network interface and is added in addition to the Docker network interface (eth0
). If we check, we'll note that since we passed the -P
flag, Docker has published the containers-exposed port to several the eth0
interface:
user@docker1:~$ docker port web1 80/tcp -> 0.0.0.0:32785 user@docker1:~$ sudo iptables -t nat -S …<Additional output removed for brevity>… -A DOCKER ! -i docker0 -p tcp -m tcp --dport 32768 -j DNAT --to-destination 172.17.0.2:80 user@docker1:~$
This proves that all of the port publishing functionality we saw earlier is still done through Docker networking constructs. The Weave interface is just added in addition to the existing Docker native network interfaces.
The second approach to connecting a container to the Weave network can be accomplished in two different ways but yields essentially the same result. Existing Docker containers can be added to the Weave network by either starting a currently stopped container using the Weave CLI, or by attaching a running container to Weave. Let's look at each approach. First, let's start a container on the host docker2
in the same way we normally do using the Docker CLI and then restart it using Weave:
user@docker2:~$ docker run -dP --name=web2 jonlangemak/web_server_2 5795d42b58802516fba16eed9445950123224326d5ba19202f23378a6d84eb1f user@docker2:~$ docker stop web2 web2 user@docker2:~$ weave start web2 web2 user@docker2:~$ docker exec web2 ip addr …<Loopback interface removed for brevity>… 15: eth0@if16: <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 17: ethwe@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP link/ether e2:22:e0:f8:0b:96 brd ff:ff:ff:ff:ff:ff inet 10.44.0.0/12 scope global ethwe valid_lft forever preferred_lft forever inet6 fe80::e022:e0ff:fef8:b96/64 scope link valid_lft forever preferred_lft forever user@docker2:~$
So as you can see, Weave has taken care of adding the Weave interface to the container when it was restarted using the Weave CLI. Similarly, we can start a second instance of our web1
container on the host docker3
and then dynamically connect it to the Weave network with the weave attach
command:
user@docker3:~$ docker run -dP --name=web1 jonlangemak/web_server_1 dabdf098964edc3407c5084e56527f214c69ff0b6d4f451013c09452e450311d user@docker3:~$ docker exec web1 ip addr …<Loopback interface removed for brevity>… 5: eth0@if6: <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@docker3:~$ user@docker3:~$ weave attach web1 10.36.0.0 user@docker3:~$ docker exec web1 ip addr …<Loopback interface removed for brevity>… 5: eth0@if6: <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 15: ethwe@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UP link/ether de:d6:1c:03:63:ba brd ff:ff:ff:ff:ff:ff inet 10.36.0.0/12 scope global ethwe valid_lft forever preferred_lft forever inet6 fe80::dcd6:1cff:fe03:63ba/64 scope link valid_lft forever preferred_lft forever user@docker3:~$
As we can see in the preceding output, the container did not have an ethwe
interface until we manually attached it to the Weave network. The attachment was done dynamically without the need to restart the container. In addition to adding containers to the Weave network, you may also dynamically remove them from Weave using the weave detach
command.
At this point, you should have connectivity between all of the containers that are now connected to the Weave network. In my case, they were allocated the following IP addresses:
web1
on host docker1
: 10.32.0.1
web2
on host docker2
: 10.44.0.0
web1
on host docker3
: 10.36.0.0
user@docker1:~$ docker exec -it web1 ping 10.44.0.0 -c 2 PING 10.40.0.0 (10.40.0.0): 48 data bytes 56 bytes from 10.40.0.0: icmp_seq=0 ttl=64 time=0.447 ms 56 bytes from 10.40.0.0: icmp_seq=1 ttl=64 time=0.681 ms --- 10.40.0.0 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.447/0.564/0.681/0.117 ms user@docker1:~$ docker exec -it web1 ping 10.36.0.0 -c 2 PING 10.44.0.0 (10.44.0.0): 48 data bytes 56 bytes from 10.44.0.0: icmp_seq=0 ttl=64 time=1.676 ms 56 bytes from 10.44.0.0: icmp_seq=1 ttl=64 time=0.839 ms --- 10.44.0.0 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.839/1.257/1.676/0.419 ms user@docker1:~$
This proves that the Weave network is working as expected and the containers are on the correct network segment.