Wyjaśnię moją konfigurację i jak rozwiązałem pełne wdzięku przeładowania:
Mam typową konfigurację z 2 węzłami z uruchomionym HAproxy i keepalived. Interfejs Keepalived śledzi interfejs dummy0, więc mogę zrobić „manekina ifconfig w dół”, aby wymusić przełączenie.
Prawdziwy problem polega na tym, że nie wiem, dlaczego „haproxy reload” nadal usuwa wszystkie ESTABLISHED połączenia :( Próbowałem „iptables flipping” zaproponowanego przez gertas, ale znalazłem pewne problemy, ponieważ wykonuje NAT w miejscu docelowym Adres IP, który nie jest odpowiednim rozwiązaniem w niektórych scenariuszach.
Zamiast tego zdecydowałem się użyć brudnego hacka CONNMARK do oznaczenia pakietów należących do NOWYCH połączeń, a następnie przekierować te oznaczone pakiety do innego węzła.
Oto zestaw reguł 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
Dwie pierwsze reguły oznaczają pakiety należące do nowych przepływów (123.123.123.123 jest utrzymywanym VIP-em używanym w haproxy do wiązania frontendów).
Trzecia i czwarta zasada oznacza pakiety pakiety FIN / RST. (Nie wiem dlaczego, cel TEE „ignoruje” pakiety FIN / RST).
Piąta reguła wysyła duplikat wszystkich oznaczonych pakietów do drugiego HAproxy (192.168.0.2).
Szósta reguła odrzuca pakiety należące do nowych przepływów, aby uniemożliwić dotarcie do pierwotnego celu.
Pamiętaj, aby wyłączyć rp_filter na interfejsach, w przeciwnym razie jądro usunie te marsjańskie pakiety.
I na koniec, pamiętaj o powracających pakietach! W moim przypadku istnieje routing asymetryczny (żądania przychodzą do klienta -> haproxy1 -> haproxy2 -> serwer WWW, a odpowiedzi wychodzą z serwera www -> haproxy1 -> klient), ale to nie ma wpływu. To działa dobrze.
Wiem, że najbardziej eleganckim rozwiązaniem byłoby użycie iproute2 do przekierowania, ale działało to tylko dla pierwszego pakietu SYN. Kiedy otrzymał ACK (trzeci pakiet 3-kierunkowego uścisku dłoni), nie oznaczył go :( Nie mogłem poświęcić dużo czasu na badanie, jak tylko zobaczyłem, że działa z celem TEE, zostawiłem go tam. Oczywiście możesz spróbować z iproute2.
Zasadniczo „płynne przeładowanie” działa w następujący sposób:
- Włączam zestaw reguł iptables i natychmiast widzę nowe połączenia przechodzące do drugiego HAproxy.
- Obserwuję „netstat -an | grep ESTABLISHED | wc -l”, aby nadzorować proces „opróżniania”.
- Gdy będzie tylko kilka (lub zero) połączeń, „ifconfig dummy0 down”, aby wymusić utrzymanie źródła do przełączenia awaryjnego, aby cały ruch trafił do innego HAproxy.
- Usuwam zestaw reguł iptables
- (Tylko dla „zachowawczej” konfiguracji keepalive) „ifconfig dummy0 up”.
Zestaw reguł IPtables można łatwo zintegrować ze skryptem start / stop:
#!/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