#!/bin/bash # # Add all anycasted IP addresses for a frontend instance to it's network namespace. # # The network namespace used is the one of the haproxy container for the instance # specified as the only argument. # # This script sets up a virtual ethernet 'cable' into the container namespace. # The outside end is called e.g. www0 for instance www, and the inside end is # always called sarimner0. # # The haproxy-start.sh script waits for sarimner0 to come up before actually # starting haproxy. # INSTANCE=$1 if [[ ! $INSTANCE ]]; then echo "Syntax: ${0} instance" exit 1 fi SCRIPTSDIR=$(dirname $0) SITE_NAME=$(${SCRIPTSDIR}/frontend-config --instance ${INSTANCE} print_site_name) if [[ ! ${SITE_NAME} ]]; then echo "$0: Could not get site_name for instance ${INSTANCE} using ${SCRIPTSDIR}/frontend-config" exit 1 fi CONTAINER="${INSTANCE}_haproxy_1" for retry in $(seq 20); do DOCKERPID=$(docker inspect '--format={{ .State.Pid }}' ${CONTAINER}) if [[ $DOCKERPID && $DOCKERPID != 0 ]]; then break fi echo "$0: Container ${CONTAINER} not found (attempt ${retry}/20)" sleep 2 done if [[ ! $DOCKERPID || $DOCKERPID == 0 ]]; then echo "$0: Could not find PID of docker container ${CONTAINER}" exit 1 fi NSPID=${DOCKERPID} mkdir -p /var/run/netns rm -f /var/run/netns/${INSTANCE} ln -s /proc/${NSPID}/ns/net /var/run/netns/${INSTANCE} echo "Container ${CONTAINER} has pid ${DOCKERPID} - symlinking /var/run/netns/${INSTANCE} to /proc/${NSPID}/ns/net" VETHHOST="${INSTANCE}" VETHCONTAINER="ve1${INSTANCE}" set -x # Enable IPv6 forwarding. Should ideally be done more selectively, but... sysctl net.ipv6.conf.all.forwarding=1 # Add a pair of virtual ethernet interfaces (think of them as a virtual cross-over ethernet cable) ip link add name ${VETHHOST} mtu 1500 type veth peer name ${VETHCONTAINER} mtu 1500 ip link set ${VETHHOST} master br-${INSTANCE} ip link set ${VETHHOST} up # Move one end of the virtual ethernet cable inside the network namespace of the docker container ip link set ${VETHCONTAINER} netns ${INSTANCE} || { echo "$0: FAILED to configure namespace, did ${CONTAINER} (pid ${DOCKERPID}) die?" exit 1 } ip netns exec ${INSTANCE} ip link set ${VETHCONTAINER} name sarimner0 # Docker likes to disable IPv6 ip netns exec ${INSTANCE} sysctl net.ipv6.conf.sarimner0.disable_ipv6=0 # DAD interferes with haproxy's first bind() of the IPv6 addresses, # and should really not be needed inside the namespace ip netns exec ${INSTANCE} sysctl net.ipv6.conf.sarimner0.accept_dad=0 # Allow bind to IP address before it is configured. # XXX Disabled since I can't decide if that would be a bug or a feature in this case. # ip netns exec ${INSTANCE} sysctl net.ipv4.ip_nonlocal_bind=1 # ip netns exec ${INSTANCE} sysctl net.ipv6.ip_nonlocal_bind=1 # Add IPv6 default gateway #sysctl net.ipv6.conf.${VETHHOST}.accept_dad=0 v6gw=$(ip -6 addr list br-${INSTANCE} | awk '/inet6/{print $2}' | head -1 | awk -F / '{print $1}') if [[ $v6gw ]]; then ip netns exec ${INSTANCE} ip -6 route add default via ${v6gw} dev sarimner0 else echo "Can't set up IPv6 routing from container, device ${VETHHOST} has no IPv6 address" fi # Add IP addresses to the network namespace of the docker container for IP in $(${SCRIPTSDIR}/frontend-config --instance ${INSTANCE} print_ips); do ip netns exec ${INSTANCE} ip addr add ${IP} dev sarimner0 ip route add ${IP} dev br-${INSTANCE} done ip netns exec ${INSTANCE} ip link set sarimner0 up