diff --git a/README.md b/README.md index 93e1169b..b14f0f68 100644 --- a/README.md +++ b/README.md @@ -55,47 +55,41 @@ two containers, one on each host. On `$HOST1` run host1$ weave launch - host1$ C=$(weave run 10.2.1.1/24 -t -i ubuntu) + host1$ weave launch-dns + host1$ weave run --name a1 -ti ubuntu -The first line starts the weave router, in a container. This needs to -be done once on each host. The required docker image for the weave -router container is downloaded automatically. There is also a `weave -setup` command for downloading this and other images required for +The first two lines start the weave router and DNS, each inside their +own container - this needs to be done once per host. Whilst the +required docker images are downloaded automatically, there is also a +`weave setup` command for downloading all the images required for weave operation; this is a strictly optional step which is especially useful for automated installation of weave and ensures that any subsequent weave commands do not encounter delays due to image downloading. -The second line runs our application container. We give it an IP -address and network, in -[CIDR notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation). -`weave run` invokes `docker run -d` with all the parameters following -the IP address and network. So we could be launching any container -this way; here we just take a stock ubuntu container and launch a -shell in it. There's also a `weave start` command, which invokes -`docker start` for starting existing containers. +The third line runs our application container, allocating it an IP +address on the weave network and registering it in DNS. `weave run` +invokes `docker run -d` behind the scenes, so we could be launching +any container this way; here we just take a stock ubuntu container and +launch a shell in it. There's also a `weave start` command, which +invokes `docker start` for starting existing containers. If our application consists of more than one container on this host we -simply launch them with a variation on that second line. +simply launch them with a variation on third second line. -The IP addresses and netmasks can be anything you like, but make sure -they don't conflict with any IP ranges in use on the hosts or IP -addresses of external services the hosts or containers need to connect -to. The same IP range must be used everywhere, and the individual IP -addresses must, of course, be unique. - -We repeat similar steps on `$HOST2`... +Next we repeat similar steps on `$HOST2`... host2$ weave launch $HOST1 - host2$ C=$(weave run 10.2.1.2/24 -t -i ubuntu) + host2$ weave launch-dns + host2$ weave run --name a2 -ti ubuntu -The only difference, apart from the choice of IP address for the -application container, is that we tell our weave that it should peer -with the weave on `$HOST1` (specified as the IP address or hostname, -and optional `:port`, by which `$HOST2` can reach it). NB: if there is -a firewall between `$HOST1` and `$HOST2`, you must open the weave port -(6783 by default; this can be overriden by setting `WEAVE_PORT`) for -TCP and UDP. +The only difference, apart from the name of the application container, +is that we tell our weave that it should peer with the weave on +`$HOST1` (specified as the IP address or hostname, and optional +`:port`, by which `$HOST2` can reach it). NB: if there is a firewall +between `$HOST1` and `$HOST2`, you must open the weave port (6783 by +default; this can be overriden by setting `WEAVE_PORT`) for TCP and +UDP. Note that we could instead have told the weave on `$HOST1` to connect to `$HOST2`, or told both about each other. Order does not matter here; @@ -109,21 +103,21 @@ can talk to each other... On `$HOST1`... - host1$ docker attach $C - root@28841bd02eff:/# ping -c 1 -q 10.2.1.2 - PING 10.2.1.2 (10.2.1.2): 48 data bytes - --- 10.2.1.2 ping statistics --- - 1 packets transmitted, 1 packets received, 0% packet loss - round-trip min/avg/max/stddev = 1.048/1.048/1.048/0.000 ms + host1$ docker attach a1 + root@a1:/# ping -c 1 -q a2 + PING a2.weave.local (10.160.0.2) 56(84) bytes of data. + --- a2.weave.local ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.341/0.341/0.341/0.000 ms Similarly, on `$HOST2`... - host2$ docker attach $C - root@f76829496120:/# ping -c 1 -q 10.2.1.1 - PING 10.2.1.1 (10.2.1.1): 48 data bytes - --- 10.2.1.1 ping statistics --- - 1 packets transmitted, 1 packets received, 0% packet loss - round-trip min/avg/max/stddev = 1.034/1.034/1.034/0.000 ms + host2$ docker attach a2 + root@a2:/# ping -c 1 -q a1 + PING a1.weave.local (10.128.0.2) 56(84) bytes of data. + --- a1.weave.local ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.366/0.366/0.366/0.000 ms So there we have it, two containers on separate hosts happily talking to each other. diff --git a/site/features.md b/site/features.md index ecae8862..478968e0 100644 --- a/site/features.md +++ b/site/features.md @@ -9,6 +9,7 @@ Weave has a few more features beyond those illustrated by the [basic example](https://github.com/weaveworks/weave#example): * [Virtual ethernet switch](#virtual-ethernet-switch) + * [Manual addressing](#manual-addressing) * [Application isolation](#application-isolation) * [Dynamic network attachment](#dynamic-network-attachment) * [Security](#security) @@ -35,18 +36,18 @@ connected. Containers can easily access services from each other; e.g. in the container on `$HOST1` we can start a netcat "service" with - root@28841bd02eff:/# nc -lk -p 4422 + root@a1:/# nc -lk -p 4422 and then connect to it from the container on `$HOST2` with - root@f76829496120:/# echo 'Hello, world.' | nc 10.2.1.1 4422 + root@a2:/# echo 'Hello, world.' | nc a1 4422 Note that *any* protocol is supported. Doesn't even have to be over TCP/IP, e.g. a netcat UDP service would be run with - root@28841bd02eff:/# nc -lu -p 5533 + root@a1:/# nc -lu -p 5533 - root@f76829496120:/# echo 'Hello, world.' | nc -u 10.2.1.1 5533 + root@a2:/# echo 'Hello, world.' | nc -u a1 5533 We can deploy the entire arsenal of standard network tools and applications, developed over decades, to configure, secure, monitor, @@ -55,47 +56,104 @@ now re-use the same tools and techniques when deploying applications as containers as we would have done when deploying them 'on metal' in our data centre. +### Manual addressing + +The examples so far have leveraged weave's [address allocation](#ipam) +and [discovery](#dns) features, meaning that we've not had to concern +ourselves with IP addresses at all. It is, however, possible to +specify address and network explicitly using [CIDR +notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation) +- let's see how the first example would have looked: + +On $HOST1: + + host1$ C=$(weave run 10.2.1.1/24 -ti ubuntu) + +And $HOST2: + + host2$ C=$(weave run 10.2.1.2/24 -ti ubuntu) + +Then on $HOST1... + + host1$ docker attach $C + root@28841bd02eff:/# ping -c 1 -q 10.2.1.2 + PING 10.2.1.2 (10.2.1.2): 48 data bytes + --- 10.2.1.2 ping statistics --- + 1 packets transmitted, 1 packets received, 0% packet loss + round-trip min/avg/max/stddev = 1.048/1.048/1.048/0.000 ms + +Similarly, on $HOST2... + + host2$ docker attach $C + root@f76829496120:/# ping -c 1 -q 10.2.1.1 + PING 10.2.1.1 (10.2.1.1): 48 data bytes + --- 10.2.1.1 ping statistics --- + 1 packets transmitted, 1 packets received, 0% packet loss + round-trip min/avg/max/stddev = 1.034/1.034/1.034/0.000 ms + +The IP addresses and netmasks can be anything you like, but make sure +they don't conflict with any IP ranges in use on the hosts (including +those delegated to IPAM) or IP addresses of external services the +hosts or containers need to connect to. The same IP range must be used +everywhere, and the individual IP addresses must, of course, be +unique. + ### Application isolation A single weave network can host multiple, isolated applications, with each application's containers being able to communicate with each other but not containers of other applications. -To accomplish that, we assign each application a different subnet. So, -in the above example, if we wanted to add another application similar -to, but isolated from, our first, we'd launch the containers with... +To accomplish that, we assign each application a different subnet. +Let's begin by configuring weave's allocator to manage multiple +subnets: - host1$ D=$(weave run 10.2.2.1/24 -t -i ubuntu) - host2$ D=$(weave run 10.2.2.2/24 -t -i ubuntu) + host1$ weave launch -iprange 10.2.0.0/16 -ipsubnet 10.2.1.0/24 + host1$ weave launch-dns + host2$ weave launch -iprange 10.2.0.0/16 -ipsubnet 10.2.1.0/24 $HOST1 + host2$ weave launch-dns + +This delegates the entire 10.2.0.0/16 subnet to weave, and instructs +it to allocate from 10.2.1.0/24 within that if no specific subnet is +specified. Now we can launch some containers in the default subnet: + + host1$ weave run --name a1 -ti ubuntu + host2$ weave run --name a2 -ti ubuntu + +And some more containers in a different subnet: + + host1$ weave run net:10.2.2.0/24 --name b1 -ti ubuntu + host2$ weave run net:10.2.2.0.24 --name b2 -ti ubuntu A quick 'ping' test in the containers confirms that they can talk to each other but not the containers of our first application... - host1$ docker attach $D - - root@da50502598d5:/# ping -c 1 -q 10.2.2.2 - PING 10.2.2.2 (10.2.2.2): 48 data bytes - --- 10.2.2.2 ping statistics --- - 1 packets transmitted, 1 packets received, 0% packet loss - round-trip min/avg/max/stddev = 0.562/0.562/0.562/0.000 ms - - root@da50502598d5:/# ping -c 1 -q 10.2.1.1 - PING 10.2.1.1 (10.2.1.1) 56(84) bytes of data. - --- 10.2.1.1 ping statistics --- + host1:~$ docker attach b1 + + root@b1:/# ping -c 1 -q b2 + PING b2.weave.local (10.2.2.128) 56(84) bytes of data. + --- b2.weave.local ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 1.338/1.338/1.338/0.000 ms + + root@b1:/# ping -c 1 -q a1 + PING a1.weave.local (10.2.1.2) 56(84) bytes of data. + --- a1.weave.local ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms - - root@da50502598d5:/# ping -c 1 -q 10.2.1.2 - PING 10.2.1.2 (10.2.1.2) 56(84) bytes of data. - --- 10.2.1.2 ping statistics --- + + root@b1:/# ping -c 1 -q a2 + PING a2.weave.local (10.2.1.130) 56(84) bytes of data. + --- a2.weave.local ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms + This isolation-through-subnets scheme is an example of carrying over a well-known technique from the 'on metal' days to containers. If desired, a container can be attached to multiple subnets when it is started: - host1$ weave run 10.2.2.1/24 10.2.3.1/24 -t -i ubuntu + host1$ weave run net:default net:10.2.2.0/24 -ti ubuntu NB: By default docker permits communication between containers on the same host, via their docker-assigned IP addresses. For complete @@ -117,29 +175,29 @@ to the weave network. To illustrate, we can achieve the same effect as the first example with host1$ C=$(docker run -d -t -i ubuntu) - host1$ weave attach 10.2.1.1/24 $C + host1$ weave attach $C There is a matching `weave detach` command: - host1$ weave detach 10.2.1.1/24 $C + host1$ weave detach $C You can detach a container from one application network and attach it to another: - host1$ weave detach 10.2.1.1/24 $C - host1$ weave attach 10.2.2.1/24 $C + host1$ weave detach net:default $C + host1$ weave attach net:10.2.2.0/24 $C or attach a container to multiple application networks, effectively sharing it between applications: - host1$ weave attach 10.2.1.1/24 $C - host1$ weave attach 10.2.2.1/24 $C + host1$ weave attach net:default + host1$ weave attach net:10.2.2.0/24 Finally, multiple addresses can be attached or detached with a single invocation: - host1$ weave attach 10.2.1.1/24 10.2.2.1/24 10.2.3.1/24 $C - host1$ weave detach 10.2.1.1/24 10.2.2.1/24 10.2.3.1/24 $C + host1$ weave attach net:default net:10.2.2.0/24 net:10.2.3.0/24 $C + host1$ weave detach net:default net:10.2.2.0/24 net:10.2.3.0/24 $C ### Security @@ -174,31 +232,38 @@ anywhere. Let's say that in our example we want `$HOST2` to have access to the application containers. On `$HOST2` we run - host2$ weave expose 10.2.1.102/24 + host2$ weave expose -choosing an unused IP address in the application subnet. (There is a -corresponding 'hide' command to revert this step.) +(There is a corresponding 'hide' command to revert this step.) -Now +Now, after finding allocated IPs via `weave ps` - host2$ ping 10.2.1.2 + host2$ weave ps weave:expose + weave:expose 02:80:5c:02:f1:b2 10.2.1.132/24 + + host1$ weave ps a1 + a1 1e:88:d7:5b:77:68 10.2.1.2/24 + +this + + host2$ ping 10.2.1.132 will work. And, more interestingly, - host2$ ping 10.2.1.1 + host2$ ping 10.2.1.2 will work too, which is talking to a container that resides on `$HOST1`. Multiple subnet addresses can be exposed or hidden with a single invocation: - host2$ weave expose 10.2.1.102/24 10.2.2.102/24 - host2$ weave hide 10.2.1.102/24 10.2.2.102/24 + host2$ weave expose net:default net:10.2.2.0/24 + host2$ weave hide net:default net:10.2.2.0/24 Finally, exposed addresses can be added to weaveDNS by supplying a fully-qualified domain name: - host2$ weave expose 10.2.1.102/24 -h exposed.weave.local + host2$ weave expose -h exposed.weave.local ### Service export @@ -213,18 +278,21 @@ a container on `$HOST1`, accessible to the outside world via `$HOST2`. First we need to expose the application network to `$HOST2`, as explained [above](#host-network-integration), i.e. - host2$ weave expose 10.2.1.102/24 + host2$ weave expose Then we add a NAT rule to route from the outside world to the destination container service. + host1$ weave ps a1 + a1 1e:88:d7:5b:77:68 10.2.1.2/24 + host2$ iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 2211 \ - -j DNAT --to-destination 10.2.1.1:4422 + -j DNAT --to-destination 10.2.1.2:4422 Here we are assuming that the "outside world" is connecting to `$HOST2` via 'eth0'. We want TCP traffic to port 2211 on the external IPs to be routed to our 'nc' service, which is running on port 4422 in the -container with IP 10.2.1.1. +container a1. With the above in place, we can connect to our 'nc' service from anywhere with @@ -253,12 +321,15 @@ First we need to expose the application network to the host, as explained [above](#host-network-integration), this time on `$HOST1`, i.e. - host1$ weave expose 10.2.1.101/24 + host1$ weave expose -h host1.weave.local Then we add a NAT rule to route from the above IP to the destination service. - host1$ iptables -t nat -A PREROUTING -p tcp -d 10.2.1.101 --dport 3322 \ + host1$ weave ps weave:expose + weave:expose 66:46:f5:ac:7b:c9 10.2.1.3/24 + + host1$ iptables -t nat -A PREROUTING -p tcp -d 10.2.1.3 --dport 3322 \ -j DNAT --to-destination $HOST3:2211 This allows any application container to reach the service by @@ -269,7 +340,7 @@ service on port 2211, e.g. then we can connect to it from our application container on `$HOST2` with - root@f76829496120:/# echo 'Hello, world.' | nc 10.2.1.101 3322 + root@a2:/# echo 'Hello, world.' | nc host1 3322 The same command will work from any application container. @@ -278,7 +349,7 @@ The same command will work from any application container. Importing a service provides a degree of indirection that allows late and dynamic binding, similar to what can be achieved with a proxy. In our example, application containers are unaware that the service they -are accessing at `10.2.1.101:3322` is in fact residing on +are accessing at `10.2.1.3:3322` is in fact residing on `$HOST3:2211`. We can point application containers at another service location by changing the above NAT rule, without having to alter the applications themselves. @@ -300,14 +371,17 @@ In our example above, the netcat service on `$HOST3` is imported into weave via `$HOST1`. We can export it on `$HOST2` by first exposing the application network with - host2$ weave expose 10.2.1.102/24 + host2$ weave expose and then adding a NAT rule which routes traffic from the `$HOST2` network (i.e. anything which can connect to `$HOST2`) to the service endpoint in the weave network + host1$ weave ps weave:expose + weave:expose 66:46:f5:ac:7b:c9 10.2.1.3/24 + host2$ iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 4433 \ - -j DNAT --to-destination 10.2.1.101:3322 + -j DNAT --to-destination 10.2.1.3:3322 Now any host on the same network as `$HOST2` can access the service with