ฉันจะอธิบายการตั้งค่าของฉันและฉันจะแก้ไข reloads ที่สง่างามได้อย่างไร:
ฉันมีการตั้งค่าทั่วไปที่มี 2 โหนดที่ทำงาน HAproxy และเก็บไว้ ติดตามส่วนต่อประสาน dummy0 ดังนั้นฉันสามารถทำ "ifconfig dummy0 down" เพื่อบังคับให้สลับ
ปัญหาที่แท้จริงคือฉันไม่รู้ว่าทำไม "haproxy reload" ยังคงปล่อยการเชื่อมต่อที่สร้างไว้ทั้งหมด :( ฉันลอง "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 แบบ keepalived ที่ใช้บน 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" เพื่อดูแลกระบวนการ "draining"
- เมื่อมีการเชื่อมต่อเพียงไม่กี่ (หรือเป็นศูนย์) ให้ "ifconfig dummy0 down" เพื่อบังคับให้เก็บข้อมูลไว้เป็น failover ดังนั้นทราฟฟิกทั้งหมดจะไปยัง HAproxy อื่น
- ฉันลบชุดกฎ iptables
- (เฉพาะสำหรับ "การไม่กำหนดค่าล่วงหน้า" กำหนดค่า keepalive) "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