This commit is contained in:
Bryan Boreham committed 2014-09-25 13:55:44 +01:00
commit 707041c7d0
7 files changed
+138 -26

No files matched your search

+44
View File
@@ -188,6 +188,35 @@ each other but not the containers of our first application...
This isolation-through-subnets scheme is an example of carrying over a
well-known technique from the 'on metal' days to containers.
### Dynamic network attachment
In some scenarios containers are started independently, e.g. via some
existing tool chain, or require more complex startup sequences than
provided by `weave run`. And sometimes the decision which application
network a container should be part of is made post startup. For these
situations, weave allows an existing, running container to be attached
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.0.1.1/24 $C
There is a matching `weave detach` command:
host1# weave detach 10.0.1.1/24 $C
You can detach a container from one application network and attach it
to another:
host1# weave detach 10.0.1.1/24 $C
host1# weave attach 10.0.2.1/24 $C
or attach a container to multiple application networks, effectively
sharing it between applications:
host1# weave attach 10.0.1.1/24 $C
host1# weave attach 10.0.2.1/24 $C
### Security
In order to connect containers across untrusted networks, weave peers
@@ -435,6 +464,21 @@ Any running application containers will permanently lose connectivity
with the weave network and have to be restarted in order to
re-connect.
### Reboots
When a host reboots, docker's default behaviour is to restart any
containers that were running. Since weave relies on special network
configuration outside of the containers, the weave network will not
function in this state.
To remedy this, stop and re-launch the weave container, and re-attach
the application containers with `weave attach`.
For a more permanent solution,
[disable Docker's auto-restart feature](https://docs.docker.com/articles/host_integration/)
and create appropriate startup scripts to launch weave and run
application containers from your favourite process manager.
## Installation with Boot2Docker
If you are running Docker inside the Boot2Docker VM, e.g. because you
+2 -3
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"log"
"math"
"math/rand"
"net"
"time"
@@ -59,7 +58,7 @@ func (cm *ConnectionMaker) String() string {
}
func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) {
timer := time.NewTimer(math.MaxInt64)
timer := time.NewTimer(MaxDuration)
run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) }
for {
select {
@@ -131,7 +130,7 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration {
})
now := time.Now() // make sure we catch items just added
after := time.Duration(math.MaxInt64)
after := MaxDuration
for address, target := range cm.targets {
if our_connected_targets[address] {
delete(cm.targets, address)
+2
View File
@@ -2,6 +2,7 @@ package weave
import (
"time"
"math"
)
const (
@@ -23,6 +24,7 @@ const (
FragTestInterval = 5 * time.Minute
PMTUVerifyAttempts = 8
PMTUVerifyTimeout = 10 * time.Millisecond // gets doubled with every attempt
MaxDuration = time.Duration(math.MaxInt64)
)
const (
+7 -2
View File
@@ -40,7 +40,7 @@ func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *Pca
if err = inactive.SetSnapLen(snaplen); err != nil {
return
}
if err = inactive.SetTimeout(-1); err != nil {
if err = inactive.SetTimeout(MaxDuration); err != nil {
return
}
if err = inactive.SetImmediateMode(true); err != nil {
@@ -60,7 +60,12 @@ func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *Pca
}
func (pi *PcapIO) ReadPacket() (data []byte, err error) {
data, _, err = pi.handle.ZeroCopyReadPacketData()
for {
data, _, err = pi.handle.ZeroCopyReadPacketData()
if err == nil || err != pcap.NextErrorTimeoutExpired {
break
}
}
return
}
+1 -1
View File
@@ -3,4 +3,4 @@ MAINTAINER Zettio weave@zett.io
WORKDIR /home/weave
ADD ./weaver /home/weave/
CMD []
ENTRYPOINT ["/home/weave/weaver", "-iface", "ethwe", "-wait"]
ENTRYPOINT ["/home/weave/weaver", "-iface", "ethwe", "-wait", "5"]
+9 -6
View File
@@ -18,17 +18,19 @@ import (
"time"
)
func ensureInterface(ifaceName string, wait bool) (iface *net.Interface, err error) {
func ensureInterface(ifaceName string, wait int) (iface *net.Interface, err error) {
iface, err = findInterface(ifaceName)
if err == nil || !wait {
if err == nil || wait == 0 {
return
}
log.Println("Waiting for interface", ifaceName, "to come up")
for err != nil {
for ; err != nil && wait > 0; wait -= 1 {
time.Sleep(1 * time.Second)
iface, err = findInterface(ifaceName)
}
log.Println("Interface", ifaceName, "is up")
if err == nil {
log.Println("Interface", ifaceName, "is up")
}
return
}
@@ -47,6 +49,7 @@ func main() {
log.SetPrefix(weave.Protocol + " ")
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
log.Println(os.Args)
procs := runtime.NumCPU()
// packet sniffing can block an OS thread, so we need one thread
@@ -60,7 +63,7 @@ func main() {
ifaceName string
routerName string
password string
wait bool
wait int
debug bool
prof string
peers []string
@@ -71,7 +74,7 @@ func main() {
flag.StringVar(&ifaceName, "iface", "", "name of interface to read from")
flag.StringVar(&routerName, "name", "", "name of router (defaults to MAC)")
flag.StringVar(&password, "password", "", "network password")
flag.BoolVar(&wait, "wait", false, "wait for interface to be created and come up")
flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (defaults to 0, i.e. don't wait)")
flag.BoolVar(&debug, "debug", false, "enable debug logging")
flag.StringVar(&prof, "profile", "", "enable profiling and write profiles to given path")
flag.IntVar(&connLimit, "connlimit", 10, "connection limit (defaults to 10, set to 0 for unlimited)")
+73 -14
View File
@@ -3,8 +3,10 @@ set -e
usage() {
echo "Usage:"
echo "weave launch <ipaddr>/<subnet> [-passwd <passwd>] <peer_host> ..."
echo "weave launch <ipaddr>/<subnet> [-password <password>] <peer_host> ..."
echo "weave run <ipaddr>/<subnet> <docker run args> ..."
echo "weave attach <ipaddr>/<subnet> <container_id>"
echo "weave detach <ipaddr>/<subnet> <container_id>"
echo "weave expose <ipaddr>/<subnet>"
echo "weave hide <ipaddr>/<subnet>"
echo "weave status"
@@ -101,7 +103,7 @@ stop_masquerading() {
}
# the following borrows from https://github.com/jpetazzo/pipework
configure_container_networking() {
container_netns_preamble() {
DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' $1)
[ "$DOCKERPID" = 0 ] && {
echo "Container $1 not running." >&2
@@ -122,7 +124,41 @@ configure_container_networking() {
GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}"
IP_TMPFILE=/tmp/weave_ip_output_$$
rm -f $IP_TMPFILE
if ip link add name $LOCAL_IFNAME mtu $MTU type veth peer name $GUEST_IFNAME mtu $MTU >$IP_TMPFILE 2>&1 ; then
return 0
}
container_netns_postamble() {
if [ "$EXITCODE" -ne 0 ] ; then
if ! ps -p $DOCKERPID >/dev/null 2>&1 ; then
echo "Container $1 died" >&2
else
echo "Failure during network configuration for container $1:" >&2
cat $IP_TMPFILE >&2
fi
fi
rm -f $IP_TMPFILE
rm -f /var/run/netns/$NSPID
}
# Attach Container-ID $1 to the weave network at CIDR address $2,
# creating a virtual ethernet device if necessary.
# Also turn off tx offload on device $3 inside the namespace.
attach() {
container_netns_preamble $1
# If veth name already exists then assume we set it up already;
# just add the IP address, if it's not already there
if ip link show $LOCAL_IFNAME >/dev/null 2>&1 ; then
if ! (ip netns exec $NSPID ip addr list dev $CONTAINER_IFNAME | grep -qF $2) 2>$IP_TMPFILE ; then
if ip netns exec $NSPID ip addr add $2 dev $CONTAINER_IFNAME 2>$IP_TMPFILE ; then
EXITCODE=0 # succeeded in adding the address
fi
else
EXITCODE=0 # address was there already
fi
elif ip link add name $LOCAL_IFNAME mtu $MTU type veth peer name $GUEST_IFNAME mtu $MTU >$IP_TMPFILE 2>&1 ; then
if (ip link set $LOCAL_IFNAME master $BRIDGE &&
ip link set $LOCAL_IFNAME up &&
ip link set $GUEST_IFNAME netns $NSPID) >$IP_TMPFILE 2>&1
@@ -138,18 +174,32 @@ configure_container_networking() {
fi
fi
if [ "$EXITCODE" -ne 0 ] ; then
if ! ps -p $DOCKERPID >/dev/null 2>&1 ; then
echo "Container $1 died" >&2
else
echo "Failure during network configuration for container $1:" >&2
cat $IP_TMPFILE >&2
container_netns_postamble $1
return $EXITCODE
}
# Detach Container-ID $1 at CIDR address $2 from the weave network
# removing the virtual ethernet device if there are no more addresses
detach() {
container_netns_preamble $1
if (ip netns exec $NSPID ip addr list dev $CONTAINER_IFNAME | grep -qF $2) 2>$IP_TMPFILE ; then
if ip netns exec $NSPID ip addr del $2 dev $CONTAINER_IFNAME 2>$IP_TMPFILE ; then
# if no inet addresses remain then delete the veth
if [ -z "$(ip netns exec $NSPID ip -f inet addr list dev ethwe 2>$IP_TMPFILE)" ] ; then
if ip link del $LOCAL_IFNAME type veth 2>$IP_TMPFILE ; then
EXITCODE=0
fi
else
EXITCODE=0
fi
fi
else
EXITCODE=0
fi
rm -f $IP_TMPFILE
rm -f /var/run/netns/$NSPID
container_netns_postamble $1
return $EXITCODE
}
@@ -186,7 +236,7 @@ case "$COMMAND" in
# restarts.
MACADDR=`cat /sys/class/net/$BRIDGE/address`
CONTAINER=$(docker run --privileged -d --name=weave -p 6783:6783/tcp -p 6783:6783/udp $WEAVE_DOCKER_ARGS zettio/weave -name $MACADDR "$@")
configure_container_networking $CONTAINER $IPADDR eth0
attach $CONTAINER $IPADDR eth0
echo $CONTAINER
;;
status)
@@ -223,9 +273,18 @@ case "$COMMAND" in
shift 1
create_bridge
CONTAINER=$(docker run -d "$@")
configure_container_networking $CONTAINER $IPADDR $CONTAINER_IFNAME
attach $CONTAINER $IPADDR $CONTAINER_IFNAME
echo $CONTAINER
;;
attach)
[ $# -gt 1 ] || usage
create_bridge
attach $2 $1 $CONTAINER_IFNAME
;;
detach)
[ $# -gt 1 ] || usage
detach $2 $1
;;
expose)
[ $# -gt 0 ] || usage
IPADDR=$1