Поради една или друга причина ми се наложи да правя Load Balance между два доставчика. Реших да си спестя голяма част от работата и да го оравновеся на всяка нова връзка.
Ровейки из StackOverflow и ServerFault попаднах на различни инструменти, които позволяват това да се направи … и разбира се опитах … и се провалих с гръм и трясък. Вторият опит беше по … читав, след като схванах къде бъркам … но трябваше да ревъртна защото mail server-а ми (docker image) не можеше да праща мейли. Днес реших и този проблем.
За този материал съм се водил от следните линкове:
https://serverfault.com/questions/93678/load-balancing-nat-ing-multiple-isp-connections-on-linux
linux-ip.net/html/routing-tables.html
И от резултатите от използването на този tool:
Имам малък сървър, който го играе едновременно border device на домашната ми мрежа и web/mail/xmpp хостинг сървър на няколко малки и средни проекта, за които се грижа (един от тях е този блог). Mail server-a от доста време е на docker, но на скоро започнах да качвам и част от нещата които хоствам в docker (нападна ме един WordPress вирус и реших че капсулация на проектите е най-добре).
Доставчика ми за последните 10 години е A1 (бившите SpectrumNet) и почти съм нямал проблеми с тях. Преди известно време обаче ми се наложи да си пусна един Vivacom-ски нет по друг повод и на друг адрес, но после ми увисна не използваем. За това реших да си го закача като втори доставчик.
Тъй като няма как да агрегирам двата доставчика, мога да им направя Load balance на ниво заявка – всяка отделна конекция минава през различен доставчик. Докато се рових обаче попаднах на интересен подход … по-скоро два допълващи се такива – ip route nexthop и iptables mangle.
На практика основната работа се върши от ip route nexthop, който е един много кратък и приятен ред:
ip route add default scope global nexthop via $ISP1_GW dev eth0 weight 1 nexthop via $ISP2_GW dev eth2 weight 1
Дори само този ред ви позволява да подкарате и двата доставчика паралелно, макар, че не е нито фин нито красив метод да се направи това. Още повече че този тип заявки не гарантират NAT-инг на мрежата зад border устройството.
След малко повече четене, се оказа че по-добър вариант е да се създадат две отдел route таблици, които да съдържат пътищата които ще се използват от цялата система.
По подразбиране ip route show показва следното:
default via 78.83.64.1 dev eth0 proto dhcp src 78.83.66.198 metric 202 default via 212.5.146.1 dev eth2 proto dhcp src 212.5.147.104 metric 203 78.83.64.0/20 dev eth0 proto dhcp scope link src 78.83.66.198 metric 202 127.0.0.0/8 dev lo scope link 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 192.168.0.0/24 dev eth3 proto kernel scope link src 192.168.0.254 192.168.10.0/24 via 192.168.10.2 dev tun0 192.168.10.2 dev tun0 proto kernel scope link src 192.168.10.1 212.5.146.0/23 dev eth2 proto dhcp scope link src 212.5.147.104 metric 203
За да можем да разделим трафика обаче, трябва да разделим в две отделни групи и съответно да сложим нужните route-ове. Стъпките са следните:
Или целият код изглежда по този начин:
ip route flush all ip rule flush # Add default rules ip rule add from all lookup main pref 32766 ip rule add from all lookup default pref 32767 # Flush both route tables ip route flush table A1 ip route flush table VIVACOM # Add main table routes ip route add 78.83.64.0/20 dev eth0 src $ISP1_IP ip route add 192.168.0.0/24 dev eth3 src 192.168.0.254 ip route add 212.5.146.0/23 dev eth2 src $ISP2_IP ip route add 127.0.0.0/8 dev lo scope link ip route add 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 ip route add 192.168.10.0/24 via 192.168.10.2 dev tun0 ip route add 192.168.10.2 dev tun0 proto kernel scope link src 192.168.10.1 #add routes to A1 table with the default gateway ip route add table A1 default dev eth0 via $ISP1_GW ip route add table A1 78.83.64.0/20 dev eth0 src $ISP1_IP ip route add table A1 192.168.0.0/24 dev eth3 src 192.168.0.254 ip route add table A1 212.5.146.0/23 dev eth2 src $ISP2_IP ip route add table A1 127.0.0.0/8 dev lo scope link ip route add table A1 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 ip route add table A1 192.168.10.0/24 via 192.168.10.2 dev tun0 ip route add table A1 192.168.10.2 dev tun0 prot kernel scope link src 192.168.10.1 #Add rule for A1 table and mark packets for it ip rule add from $ISP1_IP table A1 ip rule add fwmark 1 table A1 #Add routes for VIVACOM table with default garway ip route add table VIVACOM default dev eth2 via $ISP2_GW ip route add table VIVACOM 78.83.64.0/20 dev eth0 src $ISP1_IP ip route add table VIVACOM 192.168.0.0/24 dev eth3 src 192.168.0.254 ip route add table VIVACOM 212.5.146.0/23 dev eth2 src $ISP2_IP ip route add table VIVACOM 127.0.0.0/8 dev lo scope link ip route add table VIVACOM 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 ip route add table VIVACOM 192.168.10.0/24 via 192.168.10.2 dev tun0 ip route add table VIVACOM 192.168.10.2 dev tun0 proto kernel scope link src 192.168.10.1 #Add rule for VIVACOM and mark packets ip rule add from $ISP2_IP table VIVACOM ip rule add fwmark 2 table VIVACOM #This is where magic happens - this alternates the packets from different ISPs ip route add default scope global nexthop via $ISP1_GW dev eth0 weight 1 nexthop via $ISP2_GW dev eth2 weight 1
И всички пътища са добавени за да бъдат използвани от всички таблици. И всяка сесия сменя позицията си … Но това създава малко проблеми … все пак трябва и NAT …
За NAT или Network Address Translation се грижи iptables и по специално специалната mangle таблица, както и –mark опцията на iptables. Ето и как изглежда идеята зад промените на iptables:
Ето и как изглежда кода:
#CONNTRACK for load balancing (PREROUTING) iptables -t mangle -N A1 iptables -t mangle -A A1 -j MARK --set-mark 1 iptables -t mangle -A A1 -j CONNMARK --save-mark iptables -t mangle -N VIVACOM iptables -t mangle -A VIVACOM -j MARK --set-mark 2 iptables -t mangle -A VIVACOM -j CONNMARK --save-mark iptables -t mangle -A PREROUTING -i $LAN -s 192.168.0.0/24 -m conntrack --ctstate NEW -m statistic --mode random --probability 1 -j VIVACOM iptables -t mangle -A PREROUTING -i $LAN -s 192.168.0.0/24 -m conntrack --ctstate NEW -m statistic --mode random --probability 0.5 -j A1 iptables -t mangle -A PREROUTING -i $LAN -s 192.168.0.0/24 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark iptables -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate NEW -m statistic --mode random --probability 1 -j A1 iptables -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark iptables -t mangle -A PREROUTING -i $WAN -m conntrack --ctstate NEW -j A1 iptables -t mangle -A PREROUTING -i $WAN -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark iptables -t mangle -A PREROUTING -i $WAN2 -m conntrack --ctstate NEW -j VIVACOM iptables -t mangle -A PREROUTING -i $WAN2 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark
Ако и вие като мен имате OpenVPN инсталиран, добавте следното към конфигурацията на сървъра:
multihome
multihome позволява връзването в такава ситуация …
От време на време отварянето на интернет страници ще има проблем. Предполагам, че това се получава заради загубата на DNS заявка – тъй като всеки ISP си има DNS – ако не клиента не може да останови връзка с DNS-а защото минава през другия route … ще дропва страници … За сега не съм намерил решение на този проблем.
Поакзаният по-горе метод предполага, че и двата доставчика предоставят еднакви скорости. Моля ви анстройте си weight в ip route частта и probability в iptable частта …
Този метод не покрива DNS и HTTP Server round-robin – сървърите ви продължават да използват 1 IP …
Не забравяйте да си добавите POSTROUTING MASQUAREDE правилата и за двата доставчика:
iptables -A POSTROUTING -t nat -o $WAN -j MASQUERADE
iptables -A POSTROUTING -t nat -o $WAN2 -j MASQUERADE
Не мисля че има домашен потребител у нас който да няма торенти. Ако искате да изпозлвате и двата доставчика – добавте си port forwarding и за двете карти:
iptables -A FORWARD -p tcp -i $WAN -d 192.168.0.1 --dport 12666 -j ACCEPT iptables -t nat -A PREROUTING -p tcp -i $WAN --dport 12666 -j DNAT --to 192.168.0.1:12666 iptables -A FORWARD -p tcp -i $WAN2 -d 192.168.0.1 --dport 12666 -j ACCEPT iptables -t nat -A PREROUTING -p tcp -i $WAN2 --dport 12666 -j DNAT --to 192.168.0.1:12666
Еми това е от мен … както винаги това ръководство е написано по-скоро за да не забравя как съм го направил аз, но може да е полезно за някого … Ако имате въпроси или предложения – не се притеснявайте да питате … ако някой намери решение за DNS проблема … също да пише …
Ваш,
Lucifer
Вашият коментар