セットアップと、グレースフルリロードの解決方法を説明します。
HAproxyとkeepalivedを実行する2つのノードを使用した一般的なセットアップがあります。Keepalivedはインターフェイスdummy0を追跡するため、「ifconfig dummy0 down」を実行して強制的にスイッチオーバーできます。
本当の問題は、「haproxy reload」がまだ確立されたすべての接続をドロップする理由がわからないことです:(gertasが提案した「iptables flipping」を試しましたが、宛先で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
最初の2つのルールは、新しいフローに属するパケットをマークします(123.123.123.123は、フロントエンドをバインドするためにhaproxyで使用されるkeepalived VIPです)。
3番目と4番目のルールは、パケットにFIN / RSTパケットをマークします。(TEEターゲットがFIN / RSTパケットを「無視」する理由はわかりません)。
5番目のルールは、マークされたすべてのパケットの複製を他のHAproxy(192.168.0.2)に送信します。
6番目のルールは、新しいフローに属するパケットをドロップして、元の宛先に到達しないようにします。
インターフェイスでrp_filterを無効にすることを忘れないでください。無効にすると、カーネルはそれらの火星のパケットをドロップします。
そして最後になりましたが、戻ってくるパケットに注意してください!私の場合、非対称ルーティングがあります(要求はクライアント-> haproxy1-> haproxy2-> webserverに送られ、応答はwebserver-> haproxy1-> clientに送られます)が、影響はありません。正常に動作します。
最もエレガントな解決策は、iproute2を使用して宛先変更を行うことですが、最初のSYNパケットに対してのみ機能します。ACK(3ウェイハンドシェイクの3番目のパケット)を受信したとき、それをマークしませんでした:(調査するのに多くの時間を費やすことができませんでした。もちろん、iproute2でお試しください。
基本的に、「グレースフルリロード」は次のように機能します。
- iptablesルールセットを有効にすると、すぐに他のHAproxyへの新しい接続が表示されます。
- 「流出」プロセスを監視するために、「netstat -an | grep ESTABLISHED | wc -l」に注目します。
- 少数の(またはゼロの)接続ができたら、「ifconfig dummy0 down」を使用してkeepalivedを強制的にフェイルオーバーするため、すべてのトラフィックは他の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