diff --git a/README.md b/README.md index 9188ef54..22092da7 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,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 +situation, 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 diff --git a/weaver/weave b/weaver/weave index e673f9f9..db6756f2 100755 --- a/weaver/weave +++ b/weaver/weave @@ -5,6 +5,8 @@ usage() { echo "Usage:" echo "weave launch / [-passwd ] ..." echo "weave run / ..." + echo "weave attach / " + echo "weave detach / " echo "weave expose /" echo "weave hide /" 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