98 lines
3.4 KiB
Bash
Executable file
98 lines
3.4 KiB
Bash
Executable file
#!/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
|