Я объясню мои настройки и как я решил изящные перезагрузки:
У меня есть типичная установка с 2 узлами под управлением HAproxy и keepalived. Keepalived отслеживает интерфейс dummy0, поэтому я могу выполнить команду ifconfig dummy0 down для принудительного переключения.
Реальная проблема в том, что, я не знаю, почему, «перезагрузка haproxy» все еще отбрасывает все УСТАНОВЛЕННЫЕ соединения :( Я попробовал «переворачивание iptables», предложенное gertas, но я нашел некоторые проблемы, потому что он выполняет NAT в месте назначения IP-адрес, который не подходит для некоторых сценариев.
Вместо этого я решил использовать грязный хак CONNMARK, чтобы пометить пакеты, принадлежащие НОВЫМ соединениям, а затем перенаправить эти помеченные пакеты на другой узел.
Вот набор правил 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
Первые два правила помечают пакеты, принадлежащие новым потокам (123.123.123.123 - это VIP с поддержкой активности, используемый на haproxy для привязки внешних интерфейсов).
Третье и четвертое правила помечают пакеты FIN / RST. (Я не знаю почему, цель TEE "игнорирует" пакеты FIN / RST).
Пятое правило отправляет дубликат всех отмеченных пакетов другому HAproxy (192.168.0.2).
Шестое правило отбрасывает пакеты, принадлежащие новым потокам, чтобы предотвратить достижение их исходного назначения.
Не забудьте отключить rp_filter на интерфейсах, иначе ядро отбросит эти марсианские пакеты.
И последнее по порядку, но не по значению, не забывайте возвращать пакеты В моем случае есть асимметричная маршрутизация (запросы приходят к клиенту -> haproxy1 -> haproxy2 -> веб-сервер, а ответы идут от веб-сервера -> haproxy1 -> клиент), но это не влияет. Работает нормально.
Я знаю, что самым элегантным решением было бы использовать iproute2 для переадресации, но он работал только для первого пакета SYN. Когда он получил ACK (3-й пакет 3-стороннего рукопожатия), он не пометил его :( Я не мог тратить много времени на исследование, как только я увидел, что он работает с целью TEE, он оставил его там. Конечно, не стесняйтесь попробовать это с iproute2.
По сути, «изящная перезагрузка» работает так:
- Я включаю набор правил iptables и сразу вижу новые соединения, идущие к другому HAproxy.
- Я слежу за «netstat -an | grep ESTABLISHED | wc -l», чтобы контролировать процесс «слива».
- Если есть только несколько (или ноль) соединений, «ifconfig dummy0 down», чтобы принудительно поддерживать keepalive в состоянии отработки отказа, поэтому весь трафик будет идти к другому HAproxy.
- Я удаляю набор правил iptables
- (Только для "keepalive config" без прерывания) "ifconfig dummy0 up".
Набор правил IPtables можно легко интегрировать в скрипт запуска / остановки:
#!/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