Я поясню свої налаштування та те, як я вирішив витончені перезавантаження:
У мене типова установка з двома вузлами, на яких працює HAproxy та кеєпалівед. Keepalived відстежує інтерфейс dummy0, тому я можу зробити "ifconfig dummy0 вниз", щоб примусити переключитися.
Справжня проблема полягає в тому, що я не знаю чому, "перезарядження haproxy" все ще скидає всі встановлені з'єднання :( я спробував "iptables flipping", запропонований 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-збережений VIP, який використовується на haproxy для прив'язки фронталів).
Третє та четверте правила позначають пакети FIN / RST. (Я не знаю чому, мета TEE "ігнорує" пакети FIN / RST).
П'яте правило надсилає дублікат усіх позначених пакетів іншому HAproxy (192.168.0.2).
Шосте правило скасовує пакети, що належать до нових потоків, щоб запобігти досягненню їх початкового місця призначення.
Не забудьте відключити rp_filter на інтерфейсах, або ядро видалить ці марсіанові пакети.
І останнє, але не менш важливе, майте на увазі повертаються пакети! У моєму випадку існує асиметрична маршрутизація (запити надходять до клієнта -> haproxy1 -> haproxy2 -> веб-сервер, а відповіді йдуть від webserver -> haproxy1 -> client), але це не впливає. Це чудово працює.
Я знаю, що найелегантніше рішення буде використовувати iproute2 для переадресації, але це працювало лише для першого пакету SYN. Коли він отримав ACK (3-й пакет трехстороннього рукостискання), він не позначив його :( Я не міг витратити багато часу на розслідування, як тільки побачив, що він працює з TEE target, він залишив його там. Звичайно, не соромтеся спробувати це з iproute2.
В основному, "витончене перезавантаження" працює так:
- Я включаю набір правил iptables і негайно бачу нові з'єднання, що йдуть до іншого HAproxy.
- Я стежу за "netstat -an | grep Встановлено | wc -l", щоб контролювати процес "зливу".
- Після того, як є лише декілька (або нульових) з'єднань, "ifconfig dummy0 down", щоб змусити переконатися у відмові, тому весь трафік буде спрямований на інший HAproxy.
- Я видаляю набір правил iptables
- (Тільки для "не випереджаючої" конфігурації збереження) "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