Настройка работы сервера на CentOS с 2 шлюзами и балансировки между ними

Вместо вступления


За основу взята более ранняя прочитанная мной статья на Хабре, которой лично мне оказалось достаточно для понимания механизма policy routing в целом — и катастрофически мало для реализации этого типа маршрутизации на сервере компании. Было 2 серьезных подводных камня, над которыми пришлось работать самостоятельно, и которые нельзя оставить без внимания:

  • Сохранение настроек в целом
  • Перебивание настроек утилитой Network Manager


Свою статью я напишу в виде той инструкции, которую написал для будущих поколений айтишников в своей фирме — так что некоторые пункты из основной статьи буду приводить либо в неизменном, либо в пересказанном для себя виде. Их буду выделять курсивом. Для полного понимания того, что здесь написано, рекомендую ознакомиться с ней полностью.

Немного практики, или чего мы хотим

А хотим мы получить маршрутизацию, которая:

  • будет отправлять данные на тот же шлюз, с которого пришел запрос
  • будет контролируемо балансировать нагрузку между шлюзами, используя т.н. «вес» (weight) шлюзов
Для этих целей будем использовать утилиту iproute2, входящую в стандартную поставку всех дистрибутивов Linux.

Выдаем IP-адреса:

ip a a 11.11.11.11/22 dev eth6
ip a a 22.22.22.22/28 dev eth5


Определяем таблицы:
Для использования более чем одного маршрута, статической маршрутизации уже недостаточно. Для OSPF наша схема слишком проста, поэтому остановимся на динамической маршрутизации с использованием таблиц.


ip route add default via 22.22.22.17 table 101
ip route add default via 11.11.8.1 table 102


Заворачиваем исходящий трафик, на шлюзы, с которых пришел входящий:

ip rule add from 22.22.22.17 table 101
ip rule add from 11.11.8.1 table 102


Думаю теперь уже объяснять смысл этих строк не надо. Аналогичным образом можно сделать доступность сервера по более чем двум шлюзам.

Балансировка трафика между аплинками
Делается одной элегантной командой:

ip route replace default scope global \
nexthop via 22.22.22.17 dev eth5 weight 3 \
nexthop via 11.11.8.1 dev eth6 weight 7


Эта запись заменит существующий default-роутинг в таблице main. При этом маршрут будет выбираться в зависимости от веса шлюза (weight). Например, при указании весов 7 и 3, через первый шлюз будет уходить 70% соединений, а через второй – 30%. Есть один момент, который при этом надо учитывать: ядро кэширует маршруты, и маршрут для какого-либо хоста через определенный шлюз будет висеть в таблице еще некоторое время после последнего обращения к этой записи. А маршрут до часто используемых хостов может не успевать сбрасываться и будет все время обновляться в кэше, оставаясь на одном и том же шлюзе. Если это проблема, то можно иногда очищать кэш вручную командой ip route flush cache.

Результат
После выполнения данной команды можно проверять доступность сервера. В принципе, можно было сказать, что на этом наша работа закончилась. Однако есть одна проблема — после перезагрузки все настройки сбросятся.

Сохранение настроек в целом

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

IP-адреса
Для начала выясняем, какой mac-address какому интерфейсу принадлежит. Выполняем команду:

ip a


И видим настройки адаптеров (mac-адреса состоят из букв a или b):
2: eth6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
    inet 11.11.11.11/22 brd 11.11.11.255 scope global eth6
3: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether bb:bb:bb:bb:bb:bb brd ff:ff:ff:ff:ff:ff
    inet 22.22.22.22/28 brd 22.22.22.31 scope global eth5

Далее создаем конфигурационные файлы настроек ifconfig с использованием полученных mac-адресов. Для этого создаем файлы с приставкой ifcfg и названием интерфейса в папке

/etc/sysconfig/network-scripts:
# cat /etc/sysconfig/network-scripts/ifcfg-eth5
DEVICE=eth5
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=none
IPV6INIT=no
IPADDR=22.22.22.22
PREFIX=28
HWADDR=bb:bb:bb:bb:bb:bb
GATEWAY=22.22.22.17
DEFROUTE=yes
NAME=eth5

# cat /etc/sysconfig/network-scripts/ifcfg-eth6
DEVICE=eth6
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=none
IPV6INIT=no
IPADDR=11.11.11.11
PREFIX=22
HWADDR=aa:aa:aa:aa:aa:aa



Создаем таблицы маршрутизации
Далее необходимо создать постоянные таблицы, присвоить им имена (чтобы было проще ориентироваться) и прописать правила использования этих таблиц:

cd /etc/iproute2/ 
echo "101 int" >> rt_tables
echo "102 ext" >> rt_tables


Теперь возвращаемся в каталог /etc/sysconfig/network-scripts и продолжаем работать там.
Создаем содержимое таблиц:

# cat route-eth5
default via 22.22.22.17 table ext
# cat route-eth6
default via 11.11.8.1 table int


Создаем правила обработки этих таблиц:

# cat rule-eth5
from 22.22.22.22 lookup ext
# cat rule-eth6
from 11.11.11.11 lookup int


Балансировка
Далее заменяем статику динамикой. Не обошлось без напильника, т.к. стартап-скрипты, описанные выше, привязываются к интерфейсам, а в нашем случае правило пишется сразу про 2 интерфейса. Поэтому решено было создать отдельный скрипт и прописать его в автозагрузку, используя стандартный механизм автозапуска Linux — /etc/rc.local. Содержимое скрипта:

# cat /etc/network.sh
#!/bin/bash
/sbin/ip route replace default scope global nexthop via 11.11.8.1 dev eth6 weight 7 nexthop via 22.22.22.17 dev eth5 weight 3
exit 0


Его путь в автозагрузке:

# cat /etc/rc.local
#!/bin/sh
touch /var/lock/subsys/local
/bin/bash /etc/network.sh


Для тех, у кого не заработало исполнение файла rc.local, прошу выполнить следующие команды:
chmod u+x /etc/rc.d/rc.local
systemctl start rc-local


В результате после перезагрузки мы получаем рабочую систему с использованием 2 независимых аплинков, трафик между которыми балансируется с помощью weight. А теперь печальная новость: ничего этого работать не будет.

Перебивание настроек утилитой Network Manager

Меньшая проблема из тех, что были на моем пути, но которая тем не менее, изрядно попортила мне нервы. Проблема данной утилиты в том, что она сохраняет и использует настройки не из основных конфигурационных файлов системы, а из своих внутренних. Поскольку стартует она вместе с X11, то есть в самую последнюю очередь, когда сеть уже запущена, она перезаписывает настройки сети, и каких-то сложных конфигураций на ней построить не получится.

Чтобы ее отключить, необходимо выполнить в консоли:

sudo /etc/init.d/NetworkManager stop
chkconfig NetworkManager off


Также, можно пойти другим путем и использовать systemctl:
systemctl disable NetworkManager
systemctl stop  NetworkManager

Результат
И вот после выполнения этого действия и перезагрузки мы получаем рабочую систему с использованием 2 независимых аплинков, трафик между которыми балансируется с помощью weight.
Поделиться публикацией

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 21

    0
    А зачем вам на сервере X11, если не секрет?
      0
      Я единственный никсоид в компании, остальные сотрудники — квалифицированные Windows-администраторы. Не хочу никого обидеть, но им через интерфейс привычнее. А вообще, опыты проводились на пустом дистрибутиве CentOS с умолчальным набором софта, в который входили и иксы.
        0
        А с активным оборудованием ваши коллеги не работают? Мне что-то подсказывает, что они знакомы с CLI как минимум. Более того, вы у них отняли NetworkManager, с помощью которого в GUI можно что-то сделать. А так им все равно придется вызывать терминал, и уже в нём править конфигурацию. Не проще им было взять банальный PuTTY (например) и не вставая с рабочего места подкрутить что-то в консоли?
        В общем, не могу одобрить подход в исполнении, несмотря на простой пример использования policy.
          0
          Простите, немного не понял. Насколько мы поняли, не позволить перезаписывать наши настройки Network Manager'у можно только этим путем.
          Опять же, нам важно, чтобы настройки сохранялись после перезагрузки, чего Network Manager сделать не позволял: да, мы можем прописать все вручную, как в части статьи «Немного практики, или чего мы хотим», но это будет работать до первой перезагрузки.
          Или все же есть какие-то другие способы сохранения таких настроек роутинга, о которых мы не знаем? Я буду только рад дополнить статью.
            0
            Вопрос как раз в том, через какой интерфейс вашим коллегам будет привычнее, а не как запретить NetworkManager перезаписывать конфигурацию. Безусловно, NetworkManager будет перезаписывать конфигурацию — это, скорее, десктопный сервис, не серверный. Но что за интерфейс вы оставили коллегам? Неужели им сложнее и непривычней зайти на сервер по SSH и что-то подправить, чем подойти к нему, увидеть X11, вызвать окошко терминала и править это что-то в нем? Опять же — если они квалифицированные Windows-администраторы, то зачем им что-то править на данном сервере?
            Я потому и ругаюсь на конкретную реализацию.
              0
              Честно говоря, не понял Вашего посыла про PuTTY и интерфейс. Все вышеописанное делал я по SSH, основную часть времени все наши сотрудники на других nix-серверах сидят по тому же ssh. Но в некоторых случаях (у нас есть некоторые приложения, требующие X11, но не на этом сервере) приходится сидеть через VNC. Посему и сложилась привычка все настраивать посредством иксов. И потому-то я так долго искал ошибку — сам-то сидел посредством ssh, а только потом понял, что настройки выставляются точь-в-точь такие, как в NetworkManager.
              0
              1) cat /etc/sysconfig/NetworkManager | grep NM_RUN_ETCNET
              NM_RUN_ETCNET_POST=yes
              2) cat /etc/net/ifaces/eth6/ifup-post
              /sbin/ip route replace default scope global nexthop via 11.11.8.1 dev eth6 weight 7 nexthop via 22.22.22.17 dev eth5 weight 3

              ALTLinux, подсистема etcnet не участвует, но позволяет рулить NetwоrkManager'ом.
                0
                1) В центоси ведь, насколько мне известно, нет etcnet? Как тогда быть с той конфигой, что есть?
                [root@serv]# cat /etc/NetworkManager/nm-system-settings.conf
                [main]
                plugins=ifcfg-rh
                

                2) У меня ifup-post лежит только в папке /etc/sysconfig/network-scripts и
                имеет весьма внушительный скрипт внутри
                [root@serv network-scripts]# cat ifup-post
                #!/bin/sh
                
                cd /etc/sysconfig/network-scripts
                . ./network-functions
                
                [ -f ../network ] && . ../network
                
                unset REALDEVICE
                if [ "$1" = --realdevice ] ; then
                    REALDEVICE=$2
                    shift 2
                fi
                
                CONFIG=$1
                source_config
                
                [ -z "$REALDEVICE" ] && REALDEVICE=$DEVICE
                
                if [ "$ISALIAS" = no ] ; then
                    /etc/sysconfig/network-scripts/ifup-aliases ${DEVICE} ${CONFIG}
                fi
                
                /etc/sysconfig/network-scripts/ifup-routes ${REALDEVICE} ${DEVNAME}
                
                
                if [ "$PEERDNS" != "no" -o -n "$RESOLV_MODS" -a "$RESOLV_MODS" != "no" ]; then
                  [ -n "$MS_DNS1" ] && DNS1=$MS_DNS1
                  [ -n "$MS_DNS2" ] && DNS2=$MS_DNS2
                  if [ -n "$DNS1" ] && ! grep -q "^nameserver $DNS1" /etc/resolv.conf &&
                   tr=`mktemp /tmp/XXXXXX` ; then
                    current_replacement="$DNS1"
                    next_replacement="$DNS2"
                    search=
                    (cat /etc/resolv.conf ; echo EOF ; echo EOF) | while read answer ; do
                        case $answer in
                            nameserver*|EOF)
                                if [ -n "$current_replacement" ] ; then
                                    echo "nameserver $current_replacement" >> $tr
                                    if [ -n "$next_replacement" ] ; then
                                        current_replacement="$next_replacement"
                                        next_replacement=
                                    else
                                        current_replacement=
                                    fi
                                else
                                    if [ "$answer" != EOF ] ; then
                                        echo "$answer" >> $tr
                                    fi
                                fi
                                ;;
                            domain*|search*)
                                if [ -n "$DOMAIN" ]; then
                                    echo "$answer" | while read key value ; do
                                        search="$search $value"
                                    done
                                else
                                    echo "$answer" >> $tr
                                fi
                                ;;
                            *)
                                echo "$answer" >> $tr
                                ;;
                        esac
                    done
                    if [ -n "$DOMAIN" ]; then
                        echo "search $DOMAIN $search" >> $tr
                    fi
                
                    # backup resolv.conf
                    cp -af /etc/resolv.conf /etc/resolv.conf.save
                
                    # maintain permissions
                    # but set umask in case it doesn't exist!
                    oldumask=`umask`
                    umask 022
                    change_resolv_conf $tr
                    rm -f $tr
                    umask $oldumask
                  fi
                fi
                
                # don't set hostname on ppp/slip connections
                if [ "$2" = "boot" -a \
                     "${DEVICE}" != lo -a \
                     "${DEVICETYPE}" != "ppp" -a \
                     "${DEVICETYPE}" != "slip" ]; then
                    if need_hostname; then
                        IPADDR=`LANG= LC_ALL= ifconfig ${DEVICE} | grep 'inet addr' |
                                awk -F: '{ print $2 } ' | awk '{ print $1 }'`
                        eval `/bin/ipcalc --silent --hostname ${IPADDR}`
                        if [ "$?" = "0" ]; then
                            set_hostname $HOSTNAME
                        fi
                    fi
                fi
                
                # Notify programs that have requested notification
                do_netreport
                
                if [ -x /sbin/ifup-local ]; then
                    /sbin/ifup-local ${DEVICE}
                fi
                
                exit 0
                


                Исходя из этого документа, я должен просто дополнить этот файл своим содержимым?
                  +1
                  1) В альте etcnet одна из фич. За СентОС не скажу, как-то не сталкивался. Просто предположил, что нечто подобное имеет место быть и там. Если там только NM — печально.
                  2) Вам решать, я бы оставил в rc.local (а ещё лучше в Autostart оконного менеджера или в ~/.xprofile — у каждого отдельного юзера), а не патчил кучу мест после каждого апдейта. Лучше включить NM обратно и добавить задержку в скрипт для того, чтобы гарантированно отработать после NM.

                  Ещё скажу, что в редакторе соединений NM (v 0.9.9.1) есть подраздел «Маршруты» c галочкой «игнорировать автоматически полученные маршруты». Возможно, это будет лучше всего.
        0
        Спасибо за статью!
        Настроил по ней Centos 7 c двумя сетевыми картами, которые смотрят на разные сети и шлюзы.
        Все работает.

        В Centos 7 всплыли вот такие приколы:

        1) Чтобы rc.local в принципе заработал надо ввести следующие команды:

        chmod u+x /etc/rc.d/rc.local
        systemctl start rc-local
        

        Без них rc.local не алё.

        2) Ну и NetworkManager прибивается вот так:

        systemctl disable NetworkManager
        systemctl stop  NetworkManager
        
          0
          Честно, про systemctl слышал поверхностно. Добавлю в пост. Что касаемо rc.local — предполагаю, что зависит от сборки, т.к. у меня запустилось сразу.
            0
            А у вас Centos 7?
              0
              На момен написания статьи была 6.2.
        0
        А как можно посмотреть/сделать что-то типа графиков нагрузки шлюзов, проблема в том, что у меня все 3 шлюза в сети eth0, можно было б разбить на eth0:1,2,3 но на них придётся ставить один мак и IP, не будет ли что-то конфликтовать?
          0
          Конечно, можно мониторить. Cacti, Zabbix, Nload к вашим услугам. Но чтобы посоветовать точнее и ёмче, мне нужно более точно понять, что у вас за система такая, что на всех трех интерфейсах должны быть одинаковые мак и IP.
            0
            у провайдера 3 шлюза, каждый даёт по 30мбит/с, вот я и хочу меж ними балансироваться на openwrt
              0
              То есть вы хотите сказать, что у вас роутер? Или сразу три роутера? Если роутер — тут мало чем смогу помочь, т.к. WRT для меня потемки, а статья про Linux для PC. Если три роутера — то де-факто у вас таки 3 разных интерфейса в сервере-агрегаторе (фантазирую) и, соответственно, три разных IP и мака.
                0
                Вот в этом то и проблема, стоит роутер у меня дома, провайдет имеет 3 шлюза между которыми раскидывает абонентов на своё усмотрение, но на каждый шлюз меня пускает, если прописать вручную. Вот и появилась идея сделать балансировку между ними. Я так понимаю в торентах я получу суммарную скорость, и так, качая с разных сайтов получу по 30мбит/с с каждого. По нормальному этого не сделать, потому что многие инструкции для 2х кабелей в роутер, на разных интерфейсах, а у меня 1.
                  0
                  Попробуйте вместо роутера кинуть кабель напрямую в сетевую карту компьютера с Linux и на интерфейсе поднять еще 2 виртуальных. Не знаю, получится ли что-то, но с роутером точно не получится :)
                    0
                    На роутере то у меня Openwrt, собственно линуха. Ваша инструкция мне понравилась, её можно завести, если один интерфейс, хочется ещё смотреть нагрузку всех каналов. ;-)

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое