Spiegherò il mio setup e come ho risolto i graziosi ricarichi:
Ho una configurazione tipica con 2 nodi con HAproxy e keepalived. Le tracce keepalived si interfacciano con dummy0, quindi posso fare un "ifconfig dummy0 down" per forzare il passaggio.
Il vero problema è che, non so perché, un "ricaricato haproxy" fa cadere ancora tutte le connessioni STABILITE :( Ho provato il "lancio di iptables" proposto da Gertas, ma ho riscontrato alcuni problemi perché esegue un NAT sulla destinazione Indirizzo IP, che non è una soluzione adatta in alcuni scenari.
Invece, ho deciso di utilizzare un hack sporco CONNMARK per contrassegnare i pacchetti appartenenti a NUOVE connessioni e quindi reindirizzare i pacchetti contrassegnati sull'altro nodo.
Ecco il set di regole di iptables:
iptables -t mangle -A PREROUTING -i eth1 -d 123.123.123.123/32 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags FIN FIN -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags RST RST -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -m mark ! --mark 0 -j TEE --gateway 192.168.0.2
iptables -t mangle -A PREROUTING -i eth1 -m mark --mark 1 -j DROP
Le prime due regole segnano i pacchetti appartenenti ai nuovi flussi (123.123.123.123 è il VIP keepalived usato sull'haproxy per legare i frontend).
La terza e la quarta regola contrassegnano i pacchetti FIN / RST. (Non so perché, il target TEE "ignora" i pacchetti FIN / RST).
La quinta regola invia un duplicato di tutti i pacchetti contrassegnati all'altro HAproxy (192.168.0.2).
La sesta regola elimina i pacchetti appartenenti a nuovi flussi per impedire il raggiungimento della destinazione originale.
Ricorda di disabilitare rp_filter su interfacce o il kernel eliminerà quei pacchetti marziani.
E, ultimo ma non meno importante, attenzione ai pacchetti di ritorno! Nel mio caso c'è un routing asimmetrico (le richieste arrivano al client -> haproxy1 -> haproxy2 -> webserver, e le risposte passano dal webserver -> haproxy1 -> client), ma non influisce. Funziona bene
So che la soluzione più elegante sarebbe quella di usare iproute2 per eseguire il trasferimento, ma ha funzionato solo per il primo pacchetto SYN. Quando ha ricevuto l'ACK (terzo pacchetto dell'handshake a 3 vie), non lo ha contrassegnato :( Non ho potuto dedicare molto tempo a indagare, non appena ho visto che funziona con il target TEE, lo ha lasciato lì. Naturalmente, sentiti libero di provarlo con iproute2.
Fondamentalmente, la "ricarica aggraziata" funziona così:
- Abilito il set di regole di iptables e vedo immediatamente le nuove connessioni che vanno all'altro HAproxy.
- Tengo d'occhio "netstat -an | grep ESTABLISHED | wc -l" per supervisionare il processo di "drenaggio".
- Una volta che ci sono solo poche (o zero) connessioni, "ifconfig dummy0 down" per forzare il keepalived al failover, quindi tutto il traffico passerà all'altro proxy HA.
- Rimuovo il set di regole di iptables
- (Solo per "keep-prevent config" keepalive config) "ifconfig dummy0 up".
Il set di regole di IPtables può essere facilmente integrato in uno script di avvio / arresto:
#!/bin/sh
case $1 in
start)
echo Redirection for new sessions is enabled
# echo 0 > /proc/sys/net/ipv4/tcp_fwmark_accept
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $f; done
iptables -t mangle -A PREROUTING -i eth1 ! -d 123.123.123.123 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags FIN FIN -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -p tcp --tcp-flags RST RST -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -i eth1 -m mark ! --mark 0 -j TEE --gateway 192.168.0.2
iptables -t mangle -A PREROUTING -i eth1 -m mark --mark 1 -j DROP
;;
stop)
iptables -t mangle -D PREROUTING -i eth1 -m mark --mark 1 -j DROP
iptables -t mangle -D PREROUTING -i eth1 -m mark ! --mark 0 -j TEE --gateway 192.168.0.2
iptables -t mangle -D PREROUTING -i eth1 -p tcp --tcp-flags RST RST -j MARK --set-mark 2
iptables -t mangle -D PREROUTING -i eth1 -p tcp --tcp-flags FIN FIN -j MARK --set-mark 2
iptables -t mangle -D PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -D PREROUTING -i eth1 ! -d 123.123.123.123 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1
echo Redirection for new sessions is disabled
;;
esac