Распределение трафика между двумя прокси-серверами Squid (на Ubuntu Server 14.04.2 LTS) подключёнными к двум интернет-провайдерам (Multi-WAN). Обновлённый вариант.

image

В общем случае для организации балансировки трафика между двумя WAN-интерфейсами на Ubuntu можно использовать способы описанные в документе Ubuntu-ru — IP-Балансировка: объединяем несколько интернет-каналов в один. В нашем случае требуется организовать немного более простую конфигурацию и поэтому способ её реализации будет несколько более прост. На уже работающих прокси-серверах Squid, собранных в конфигурацию повышенной доступности, имеется по одному WAN-интерфейсу направленному в сторону одного интернет-провайдера. Для повышения доступности Интернет для конечных пользователей мы добавим на прокси-серверы ещё по одному WAN-интерфейсу направленному в сторону другого интернет-провайдера и настроим скрипт перестроения правил маршрутизации в случае возникновения проблем с одним из провайдеров. Здесь мы рассмотрим обновлённый вариант такой настройки (без использования multipath-маршрутизации).

Тезисно общий смыл настройки и последующей работы реализуемой нами конфигурации Multi-WAN можно отразить так:

  • На двух прокси-серверах будет настроено по 2 WAN-интерфейса (2 публичных IP адреса от разных интернет-провайдеров)
  • На каждом из серверов на любой определённый момент времени только один из WAN-интерфейсов используется для определения маршрута по умолчанию, то есть весь трафик в интернет идёт через этот WAN-интерфейс. Второй WAN-интерфейс при этом системой не используется.
  • Для распределения интернет-трафика между двумя интернет-провайдерами, согласно предыдущего тезиса, на одном прокси-сервере активен (как маршрут по умолчанию) WAN-интерфейс относящийся к первому интернет-провайдеру, а на втором прокси-сервере активен WAN-интерфейс относящийся к другому провайдеру.
  • При старте системы на обоих серверах запускается скрипт проверяющий доступность каких-либо интернет-узлов (например Google и Yandex) через активный (как маршрут по умолчанию) WAN-интерфейс. Как только скрипт определит недоступность интернет-ресурсов, — выполняется перестроение маршрутизации: маршрут по умолчанию назначается на другой WAN-интерфейс.

Для большей наглядности приведу простейшую схему нашей конечной конфигурации с учётом ранее собранной конфигурации повышенной доступности с помощью UCARP:

image


Рассмотрим процесс настройки первого прокси-сервера (KOM-AD01-GW20).

Первым делом внесём изменения в файл описывающий таблицы маршрутизации используемые в системе:

sudo nano -Y sh /etc/iproute2/rt_tables

В конец файла добавим две новые таблицы маршрутизации, которые будут использоваться для работы скрипта:

#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
#1      inr.ruhep
101     provider1
102     provider2

Затем внесём изменения в файл /etc/network/interfaces.

sudo nano -Y sh /etc/network/interfaces

В параметрах описывающих первый WAN-интерфейс (в нашем примере eth1) убедимся в том, что присутствует запись о шлюзе провайдера и добавим две команды. Первая команда добавляет маршрут по умолчанию в созданную нами дополнительную таблицу маршрутизации относящуюся к конкретному провайдеру (например provider1). Вторая команда добавляет правило означающее то, что все пакеты промаркированные (fwmark) определённым тэгом (например 11) отправляются в таблицу маршрутизации относящуюся к конкретному провайдеру (например provider1). Соответственно этот WAN-интерфейс на данном сервере будет использоваться для определения маршрута по умолчанию.

Аналогичным образом добавим информацию о втором WAN-интерфейсе (eth2), только адрес шлюза провайдера здесь уже указывать не будем.

#
# WAN-1
#
auto eth1
iface eth1 inet static
        address 62.99.99.246
        netmask 255.255.255.248
gateway 62.99.99.241
up ip route add default via 62.99.99.241 dev eth1 table provider1 up ip rule add fwmark 11 table provider1 # # WAN-2 # auto eth2 iface eth2 inet static address 99.99.99.55 netmask 255.255.255.0 up ip route add default via 99.99.99.20 dev eth2 table provider2 up ip rule add fwmark 12 table provider2 #

В нашем примере адреса 62.99.99.241 (шлюз для eth1) и 99.99.99.20 (шлюз для eth2) – это адреса шлюзов интернет-провайдеров.

***

Для корректной работы скрипта нам понадобится отключить rp_filter (подробнее здесь), так как он блокирует входящие пакеты на интерфейсе от сетей, которых нет в маршрутах через этот интерфейс. Сделать это можно, например, внеся изменения в файл sysctl.conf

sudo nano -Y sh /etc/sysctl.conf

Найдём, раскомментируем и установим значения rp_filter в 0:

# Uncomment the next two lines to enable Spoof protection (reverse-path filter)
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.rp_filter=0

Сохраним файл и применим его изменения в системе:

sudo sysctl -p

После всех проделанных изменений перезагружаем сервер и проверяем результат сделанных изменений. Проверим основную таблицу маршрутизации (main)…

sudo ip route show

default via 62.99.99.241 dev eth1
10.0.0.0/8 via 10.16.8.1 dev eth0
10.16.8.0/24 dev eth0  proto kernel  scope link  src 10.16.8.20
62.99.99.240/29 dev eth1  proto kernel  scope link  src 62.99.99.246
99.99.99.0/24 dev eth2  proto kernel  scope link  src 99.99.99.55

Как видим, шлюз провайдера с первого WAN-интерфейса (eth1) определяет на текущем сервере маршрут по умолчанию (default).

Проверим две дополнительные созданные нами таблицы маршрутизации и наличие в них маршрута по умолчанию:

sudo ip route show table provider1

default via 62.99.99.241 dev eth1
sudo ip route show table provider2

default via 99.99.99.20 dev eth2

***

Далее создадим папку для хранения скрипта проверки состояния WAN-интерфейсов, в ней создадим файл скрипта и сделаем его исполняемыми для root.

sudo mkdir /etc/multi-wan
sudo touch /etc/multi-wan/check-multi-wan.sh
sudo chmod 0700 /etc/multi-wan/check-multi-wan.sh
sudo nano -Y sh /etc/multi-wan/check-multi-wan.sh

Наполним скрипт содержимым:

#!/bin/bash

GW=(62.99.99.241 99.99.99.20)
IF=(eth1 eth2)
MARK=(11 12)
DNS=(8.8.8.8 77.88.8.8)
LOG=/var/log/multi-wan.log

CHANGE=0;
STATUS=(up down)
for i in $(seq 0 $(( ${#GW[@]}-1 ))); do
  S=1

  for host in "${DNS[@]}"; do
    ping -i 0.2 -c 3 $host -m ${MARK[$i]} > /dev/null
    if [ $? -eq 0 ]; then
      C=$i
      S=0
      break
    fi
  done

  ip route show to match 0/0 | grep -q ${GW[$i]}
  if [ $S -ne $? ]; then
    echo $(date +"%F %T") ${IF[$i]} is ${STATUS[$S]} >> $LOG
    CHANGE=1
  fi

  if [ $S -eq 0 ]; then
    break
  fi

done

if [ $CHANGE -eq 0 ]; then
  exit 0
elif [ -z "$C" ]; then
  echo $(date +"%F %T") All gateways failed >> $LOG
  exit 1
fi

ip route replace default via ${GW[$C]} dev ${IF[$C]}

#

В переменной GW укажем массив шлюзов интернет-провайдеров (в скобках через пробел). В массиве должно быть столько значений, сколько WAN-интерфейсов мы настроили в файле /etc/network/interfaces.

В переменной IF укажем массив имён интерфейсов относящихся к значениям в переменной GW.

В переменной MARK укажем массив тэгов, которые будут использоваться для маркировки ICMP-пакетов генерируемых скриптом проверки. В качестве значений массива могут быть указаны, например, любые двузначные числа (целые и больше 0). Самое главное, чтобы эти значения были идентичны значениям параметра fwmark, указанного нами ранее в файле /etc/network/interfaces.

В переменной DNS укажем массив каких-либо публичных IP адресов, которые будут проверяться с помощью ping на доступность (в нашем примере используются адреса хорошо известных DNS серверов Google и Yandex).

В переменной LOG укажем месторасположения лог-файла, в который будут записываться все события перестроения default-маршрута.

Логика скрипта следующая – через активный WAN-интерфейс посылается 3 пинга на каждый из внешних публичных IP адресов из пула значений переменной DNS. В случае если все попытки завершаются неудачей – происходит перестроение default-маршрута таким образом, чтобы задействовать другой работоспособный WAN-интерфейс.

***

Теперь нам нужно настроить периодическое выполнение скрипта. Создадим для этого файл задачи cron:

sudo touch /etc/cron.d/check-multi-wan
sudo nano -Y sh /etc/cron.d/check-multi-wan

Наполним его содержимым таким образом, чтобы наш скрипт проверки Multi-WAN выполнялся раз в минуту:

#
# Regular cron job for the multipath routing
#
* * * * *   root /etc/multi-wan/check-multi-wan.sh

***

Не забываем при необходимости изменить правила iptables. Например, если прокси-серверы должны ещё обеспечивать работу NAT, как было описано ранее, добавляем соответствующие правила iptables для обоих WAN-интерфейсов: 

sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth1 -j SNAT --to-source 62.99.99.246
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth2 -j SNAT --to-source 99.99.99.55

***

На данном этапе настройку прокси сервера можно считать законченной и теперь настало время проверить работоспособность всех сделанных настроек. 

Сымитируем сбой доступности провайдера используемого для default-маршрута с помощью iptables, например так:

sudo iptables -I OUTPUT -o eth1 -j DROP

В логе при этом через минуту будет зафиксировано соответствующее событие о том, что интерфейс “опущен”:

sudo tail -f /var/log/multi-wan.log

2015-05-14 15:48:22 eth1 is down

Проверим то, как при этом изменилась конфигурация маршрутов:

sudo ip route show

default via 99.99.99.20 dev eth2
10.0.0.0/8 via 10.16.8.1 dev eth0
10.16.8.0/24 dev eth0  proto kernel  scope link  src 10.16.8.20
62.99.99.240/29 dev eth1  proto kernel  scope link  src 62.99.99.246
99.99.99.0/24 dev eth2  proto kernel  scope link  src 99.99.99.55

Как видим, заблокированный WAN-интерфейс eth1 теперь не используется для маршрута по умолчанию, и теперь весь трафик будет направляться через другой доступный WAN-интерфейс (eth2). 

Убеждаемся в том, что при этой конфигурации интернет у пользователей через данный прокси-сервер продолжает работать.

Чтобы снова включить в работу WAN-интерфейс eth1, выполняем команду удаления созданного ранее правила iptables: 

sudo iptables -D OUTPUT -o eth1 -j DROP

В логе при этом будет зафиксировано соответствующее событие о том, что интерфейс вернулся к работе:

sudo tail -f /var/log/multi-wan.log

2015-05-14 15:48:22 eth1 is down
2015-05-14 15:50:11 eth1 is up

Снова проверим конфигурацию маршрутов в таблице маршрутизации main и убедимся в том, что они перестроились (вернулись к исходному состоянию):

sudo ip route show

default via 62.99.99.241 dev eth1
10.0.0.0/8 via 10.16.8.1 dev eth0 10.16.8.0/24 dev eth0 proto kernel scope link src 10.16.8.20 62.99.99.240/29 dev eth1 proto kernel scope link src 62.99.99.246 99.99.99.0/24 dev eth2 proto kernel scope link src 99.99.99.55

***

Всю настройку второго прокси-сервера (KOM-AD01-GW21) выполняем по аналогии с первым с некоторыми изменениями. В частности, в файле /etc/network/interfaces меняем IP-адреса, а шлюз провайдера указываем уже не на первом, а на втором WAN-интерфейсе, то есть именно второй WAN-интерфейс будет определять маршрут по умолчанию для данного сервера.

#
# WAN-1
#
auto eth1
iface eth1 inet static
        address 62.99.99.245
        netmask 255.255.255.248
        up ip route add default via 62.99.99.241 dev eth1 table provider1
        up ip rule add fwmark 11 table provider1
#
# WAN-2
#
auto eth2
iface eth2 inet static
        address 99.99.99.57
        netmask 255.255.255.0
        gateway 99.99.99.20
        up ip route add default via 99.99.99.20 dev eth2 table provider2
        up ip rule add fwmark 12 table provider2
#

Далее не забываем, при необходимости, в соответствии с изменением WAN-интерфейсов внести изменения в правила iptables.

Затем в полной аналогии с первым прокси-сервером выполняем на втором сервере настройки:
добавляем две дополнительные таблицы маршрутизации в /etc/iproute2/rt_tables;
— в файле /etc/sysctl.conf отключаем rp_filter;

Создаём скрипт /etc/multi-wan/check-multi-wan.sh с тем же содержимым, что и на первом сервере за исключением того, что меняем местами значения массивов в переменных GW,IF,MARK

#!/bin/bash

GW=(99.99.99.20 62.99.99.241)
IF=(eth2 eth1)
MARK=(12 11)
DNS=(8.8.8.8 77.88.8.8)
LOG=/var/log/multi-wan.log
...

Скрипт сконструирован таким образом, что для определения маршрута по умолчанию приоритетным считает тот шлюз провайдера, который в массиве значений стоит первым. Поэтому мы и меняем на втором сервере значения соответствующих переменных.

***

В конечном итоге, скомбинировав ранее описанную настройку UCARP и описанную здесь настройку динамического перестроения default-маршрута, можно получить высоко-доступное решение по предоставлению Интернет-ресурсов конечным пользователям локальной корпоративной сети, которое по функционалу не будет уступать проприетарному Microsoft Forefront TMG (снятому кстати говоря с продаж и официальной поддержки) в массиве Enterprise Array с задействованным режимом ISP Redundancy. 

***

Справедливости ради также стоит отметить , что описанное решение по своей сути не имеет прямого отношения к Squid и может быть использовано и в других сценариях, где нужно организовать балансировку нагрузки между двумя и более серверами с несколькими WAN-интерфейсами.

***

Благодарю Владимира Леттиева (aka crux) за пошаговую инструкцию со скриптом и всестороннюю помощь в построении вышеописанной конфигурации. 

Дополнительные источники информации:

Всего комментариев: 2 Комментировать

  1. Alexey Gagarin /

    Алексей, а как вы собираете статистику с двух прокси-серверов? На каждом стоит свой Lightsquid? И как быть с kerberos-авторизацией? Используете CNAME-запись?

    1. Алексей Максимов / Автор записи

      Наш специалист разрабатывает собственный сборщик логов squid (развернут на отдельной машине) который позволит просматривать отчёты аналогичные Lightsquid по двум серверам совокупно.
      А пока эта вещь в разработке, да, используем Lightsquid на каждом сервере.

      Kerberos работает. Никаких CNAME-записей не нужно (насколько помню при использовании CNAME вообще могут быть проблемы аутентификации).
      Как настроен и работает Kerberos при использовании нескольких прокси-серверов можно понять из предыдущих заметок.
      Настройка прокси сервера Squid 3.3 на Ubuntu Server 14.04 LTS. Часть 4. Конфигурация Kerberos и NTLM
      Повышаем доступность прокси-сервера Squid с помощью UCARP с балансировкой нагрузки между двумя виртуальными серверами на базе Ubuntu Server 14.04.2

Добавить комментарий