понедельник, 25 апреля 2016 г.

Как осуществить балансировку исходящей почты.

Балансировка исходящей почты может пригодиться, когда в качестве следующего получателя (next-hop) письма есть несколько серверов. Для одного домена можно указать несколько MX записей и/или несколько IP адресов (Round robin DNS). Этот вариант широко распространен для публичного интернета. Однако, этот вариант не подходит, если вы не имеете возможность менять DNS зону. Или к примеру, для почтового сервера используемого внутри LAN: пересылка всех писем может осуществляется на next-hop, который указан в (или для определенных случаев в таблице transport). Уточню, в postfix в директиве relayhost нельзя указать перечень серверов. Усложним задачу: необходимо определять доступность next-hop серверов. Сделать требуемое позволит haproxy. Его можно развернуть на этом же почтовом сервере. Haproxy будет слушать на loopback'е, перенаправляя входящий трафик на сервера next-hop. Помимо пересылки трафика он так же будет мониторить доступность серверов. Пример конфигурации haproxy:

# cat /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon

# turn on stats unix socket
stats socket /var/lib/haproxy/stats

defaults
log global
option tcplog
option log-health-checks
option dontlognull
option redispatch
retries 3
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout check 10s
maxconn 3000

listen stats gwip:5111
mode http
stats enable
stats hide-version
stats auth admin:password
stats uri /admin?stats
stats show-desc server.domain.com

listen base_relay 127.0.0.1:5222
mode tcp
balance roundrobin
option smtpchk HELO server.domain.com
server nexthop1 ip1:25 check inter 5000 fall 3 rise 3
server nexthop2 ip2:25 check inter 5000 fall 3 rise 3
server nexthop3 ip3:25 check inter 5000 fall 3 rise 3
server nexthop4 ip4:25 check inter 5000 fall 3 rise 3

Кратко по листингу:
  • listen stats gwip:5111 — блок описания графического интерфейса статистики и управления haproxy, gwip должен быть ip сервера. Не забудьте поменять пароль!
  • listen base_relay 127.0.0.1:5222 — блок описания балансировки исходящей почты.
    • balance roundrobin — политика балансировки соединений, название говорит само за себя.
    • option smtpchk HELO server.domain.com — проверка доступности серверов next-hop на седьмом уровне модели OSI, укажите свое имя сервера.
    • server nexthop1 ip1:25 check inter 5000 fall 3 rise 3 — информация по next-hop серверу, его имя — nexthop1, ip — ip1, и параметры проверки:
      • inter - временной интервал проверки, 5000 мс.
      • fall - количество неудачных попыток подряд, после чего сервер исключается из списка балансировки соединений.
      • rise - количество удачных попыток подряд, после чего сервер возвращается в список.

Теперь осталось только поменять в конфигурации postfix адрес в директиве relayhost на 127.0.0.1:5222. Данная статья хорошо сочетается с этой публикацией. Могу добавить, что в моем случае количество проходящих писем составляет более миллиона в сутки.

воскресенье, 22 ноября 2015 г.

Имя сетевого устройства

Старое название интерфейсов, такое как к примеру eth0, кануло в лету (ну почти, иногда старые имена можно встретить). В RHEL7 используются следующие варианты схем наименования сетевого интерфейса, в порядке применения:
  1. Имя, предоставляемое аппаратным обеспечением (Firmware или BIOS), включающее порядковый номер, для устройств, расположенных на материнской плате, к примеру eno1. Если выбор имени не произведен, используется схема 2.
  2. Имя, предоставляемое аппаратным обеспечением (Firmware или BIOS), включающее порядковый номер слота PCI Express, к примеру ens1. Если выбор не произведен, используется схема 3.
  3. Имя формируется из физического положения точки подключения устройства, к примеру enp2s0. Иначе используется схема 5.
  4. Имя включает MAC устройства, к примеру enx94de80a44f0c. Эта схема по умолчанию не используется.
  5. Старая схема, где имя присваивается ядром в порядке обнаружения интерфейса, к примеру eth0 и т.д.
Это поведение по умолчанию.

Новые имена сами по себе содержат полезную информацию. Принятое соглашение о наименовании следующее: первые два символа отражают тип интерфейса:
  1. en — Ethernet.
  2. wl — беспроводная локальная сеть, WLAN.
  3. ww — беспроводная глобальная сеть, WWAN.
Далее следует тип, отражающий схему наименования, описанную выше:
  1. o<index> индекс для устройств расположенных на материнской плате.
  2. s<slot>[f<function>][d<dev_id>] сначала идет номер PCI Express слота, далее f<function> - номер функции у многофункционального PCI устройства (я не встречал таких плат) и последним идет идентификатор устройства.
  3. p<bus>s<slot>[f<function>][d<dev_id>] расположение устройства на PCI шине. Домен PCI (p<bus>) указывается только если он отличен от нулевого (это можно увидеть в больших системах). Номер функции и номер устройства аналогично предыдущему примеру.
  4. p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>] расположение устройства на USB шине, причем учитывается вся цепочка портов.
  5. x<MAC> MAC адрес.
Нужно отметить, что имя не может быть более 15 символов, это ограничение ядра.

В случае использования VLAN добавляется следующее соглашение о имени интерфейса:
  1. vlan<vlanid> — имя с полным номером vlanid, к примеру vlan0012 или имя с сокращенным vlanid — vlan12
  2. device_name.<vlanid> - имя интерфейса и VLAN ID в полном или сокращенном виде, к примеру ens3.0012 или ens3.12
Как бы глупо это не звучало, но помимо описанных соглашений о наименовании, есть еще одно, используемое при помощи утилиты udev — biosdevname (насколько я понял, возникло это соглашение по инициативе DELL и используется на их серверах). Оно имеет силу только при наличии установленного пакета biosdevname и при указании biosdevname=1 при загрузке системы. Переименования будут производится только для встроенных интерфейсов. При этом:
  1. Встроенные интерфейсы будут иметь имя типа em[123...]
  2. Интерфейсы, подключенные по шине PCI — p<slot>p<ethernet port>, к примеру p3p4
Чтобы окончательно не запутаться в теоретической части, рассмотрим более глубоко процесс присваивания имени интерфейсу по шагам. Ниже пример того что происходит, когда в системе появляется новый интерфейс:

# udevadm monitor
...
KERNEL[27783.869667] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/eth0 (net)
...
KERNEL[27783.879674] move /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/enp0s20u7u4 (net)
UDEV [27783.892038] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/enp0s20u7u4 (net)
...

Т.е. сначала интерфейс появился со старым, знакомым именем eth0, а далее стал enp0s20u7u4. Нетрудно заметить, что новое имя сразу отображает что это адаптер Ethernet (en), подключенный к USB шине через usb хаб (в имени два usb порта u7u4). Достаточно удобно.

Посмотрим, что выполняет udev над интерфейсом:

  • Шаг первый:
# udevadm test /sys/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/enp0s20u7u4
...
PROGRAM '/lib/udev/rename_device' /usr/lib/udev/rules.d/60-net.rules:1
starting '/lib/udev/rename_device'

Что происходит: правило udev /usr/lib/udev/rules.d/60-net.rules при помощи /lib/udev/rename_device, просматривает конфигурационные файлы сетевых интерфейсов - /etc/sysconfig/network-scripts/ifcfg-*, и если есть соответствие MAC адреса добавляемого интерфейса и адреса в директиве HWADDR, то имя интерфейса устанавливается в соответствии с директивой DEVICE.
Сейчас воспользуемся небольшой хитростью, чтобы процесс применения правил udev был более наглядным. Создадим конфигурационный файл ifcfg-tstif0 с именем tstif0 для нашего адаптера и вставим адаптер. Интерфейс в системе станет tstif0. Теперь удалим конфигурационный файл, и посмотрим на обработку правил еще раз, но уже для интерфейса tstif0, в конечном итоге мы должны будем получить имя enp0s20u7u4.
Запустим еще раз, первое правило не отработает, т.к. конфигурационный файл мы удалили:

PROGRAM '/lib/udev/rename_device' /usr/lib/udev/rules.d/60-net.rules:1
starting '/lib/udev/rename_device'
'/lib/udev/rename_device' [5023] exit with return code 0

  • Шаг второй, смотрим дальше:
PROGRAM '/sbin/biosdevname --policy physical -i tstif0' /usr/lib/udev/rules.d/71-biosdevname.rules:22
starting '/sbin/biosdevname --policy physical -i tstif0'
'/sbin/biosdevname --policy physical -i tstif0' [5024] exit with return code 2

Правило /usr/lib/udev/rules.d/71-biosdevname.rules реализует выше рассмотренное соглашение о именах при использовании biosdevname. Уточнение, это правило работает, если в системе установлен biosdevname, при загрузке не был использован параметр biosdevname=0, и если имя не было назначено на предыдущем шаге.

  • Шаг третий:
IMPORT builtin 'net_id' /usr/lib/udev/rules.d/75-net-description.rules:6
IMPORT builtin skip 'usb_id' /usr/lib/udev/rules.d/75-net-description.rules:8
IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/75-net-description.rules:8

На этом этапе правилом /usr/lib/udev/rules.d/75-net-description.rules, заполняются следующие директивы описания устройства: ID_NET_NAME_ONBOARD, ID_NET_NAME_SLOT, ID_NET_NAME_PATH и ID_NET_NAME_MAC. Не все директивы могут быть заполнены, поскольку не все устройства могут иметь требуемую информацию.

  • Шаг четвертый:
IMPORT builtin 'path_id' /usr/lib/udev/rules.d/80-net-setup-link.rules:5
IMPORT builtin 'net_setup_link' /usr/lib/udev/rules.d/80-net-setup-link.rules:9
Config file /usr/lib/systemd/network/99-default.link applies to device tstif0
NAME 'enp0s20u7u4' /usr/lib/udev/rules.d/80-net-setup-link.rules:11

Вот оно правило, которое устанавливает имя для интерфейса в данном случае - /usr/lib/udev/rules.d/80-net-setup-link.rules. Что по этому правило происходит: если интерфейс не был переименован на предыдущих шагах, и если не задан параметр ядра net.ifnames=0, то имя интерфейса устанавливается в соответствии с порядком по приоритету из полученных ранее директив: ID_NET_NAME_ONBOARD, ID_NET_NAME_SLOT, ID_NET_NAME_PATH. Если ни одна из директив не определена, то интерфейс остается не переименованным, т.е. старый вариант именования — eth0.
Для понимания, посмотреть возможные имена можно так:

# udevadm info /sys/class/net/tstif0 | grep ID_NET_NAME
E: ID_NET_NAME=enp0s20u7u4
E: ID_NET_NAME_MAC=enx00101402bca7
E: ID_NET_NAME_PATH=enp0s20u7u4

Можно заметить, что почти все пункты (за исключением 5 — старого именования) из стандартного соглашения о наименовании реализуются в правилах udev: 75-net-description.rules и 80-net-setup-link.rules. Можно возразить, а где наименование по MAC адресам? Включение его можно произвести правкой правила 80-net-setup-link.rules. Скопируйте его:

# cp /usr/lib/udev/rules.d/80-net-name-slot.rules /etc/udev/rules.d

И добавьте строку выделенную курсивом на листинге:

# grep -v "^#\|^$" /etc/udev/rules.d/80-net-name-slot.rules
ACTION!="add", GOTO="net_name_slot_end"
SUBSYSTEM!="net", GOTO="net_name_slot_end"
NAME!="", GOTO="net_name_slot_end"
IMPORT{cmdline}="net.ifnames"
ENV{net.ifnames}=="0", GOTO="net_name_slot_end"
NAME=="", ENV{ID_NET_NAME_MAC}!="", NAME="$env{ID_NET_NAME_MAC}"
NAME=="", ENV{ID_NET_NAME_ONBOARD}!="", NAME="$env{ID_NET_NAME_ONBOARD}"
NAME=="", ENV{ID_NET_NAME_SLOT}!="", NAME="$env{ID_NET_NAME_SLOT}"
NAME=="", ENV{ID_NET_NAME_PATH}!="", NAME="$env{ID_NET_NAME_PATH}"
LABEL="net_name_slot_end"

Не уверен, что данный вариант именования удобен.

Итак, мы обсудили несколько соглашений о наименовании сетевых интерфейсов, рассмотрели по шагам, как происходит выбор имени, попутно узнали, что net.ifnames=0 отключает новую схему наименования, и последнее замечание: не используйте имена из пространства ядра - ethX в схеме с присвоением имен через файлы ifcfg-*.



воскресенье, 15 ноября 2015 г.

Перезагрузка сервера без нервов

Последнее поколение серверов с большим количеством аппаратных ресурсов, тратят много времени на проверку оборудования при старте системы. Порой это может занять 20 минут и более. Для систем, где окно техобслуживания составляет не больше часа, обновление ОС может быть очень затруднено. Выйти из положения позволяет kexec. Kexec - это системный вызов, который загружает в память новое ядро и производит загрузку ОС с этим ядром. Фактически, kexec выполняет функцию загрузчика ОС. Естественно данный процесс загрузки отличается от нормального тем, что не производится инициализация оборудования на аппаратном уровне (UEFI), за счет этого и достигается выигрыш времени.
Синтаксис команды для загрузки нового ядра:

kexec -l kernel-image --append=command-line-options --initrd=initrd-image

где:

  • -l - путь к новому ядру
  • --append - параметры, используемые при загрузке, можно использовать текущие параметры, содержащиеся в /proc/cmdline, для этого вместо этого параметра укажите --reuse-cmdline
  • --initrd - путь к initrd/initramfs образу.

После чего необходимо дать команду на запуск нового ядра:

kexec -e

Пример:

# kexec -l /boot/vmlinuz-3.10.0-229.20.1.el7.x86_64 --reuse-cmdline --initrd=/boot/initramfs-3.10.0-229.20.1.el7.x86_64.img
# kexec -e

четверг, 5 ноября 2015 г.

Имя хоста

Имена бывают трех типов:

  • статическое (static) — то, которое задает пользователь, хранится в /etc/hostname;
  • временное (transient) — имя,  полученное посредством DHCP или mDNS, если статическое имя установлено и оно отлично от localhost, то будет использоваться статическое имя;
  • прелестное (pretty) — имя, которое можно использовать для описания хоста, к примеру «Super duper server», хранится в /etc/machine-info. Может быть полезно, когда имена машин однотипны. Больше всего умиляет, что названия как в физике, типа «прелестный кварк».

Статическое и временное имена должны состоять из символов: a-z, A-Z, 0-9, дефиса, подчеркивания и точки, длина не должна превышать 64 символа.
Посмотреть текущие имена можно следующим образом:

$ hostnamectl status

Установить все имена сразу можно командой:

# hostnamectl set-hostname имя

Если нужно изменить определенное имя, то нужно добавить --pretty, --static или --transient, к примеру:

# hostnamectl set-hostname "Super duper server" --pretty

Заметки о RHEL7



Друзья/коллеги/читатели, пишу ряд статей об использовании RHEL7. Я сознательно не рассматриваю абсолютно все возможные пути конфигурирования или выполнения базовых операций. К примеру, в статьях точно не будут рассмотрены варианты конфигурирования с помощью графической оболочки NetworkManager. Источники данных, в большинстве своем, официальные документы с сайта вендора.
Ниже будут ссылки на статьи для удобства.

Имя хоста
Имя сетевого устройства

пятница, 10 июля 2015 г.

Балансировщик трафика для Exchange 2013

Продолжим рассматривать балансировку, отказоустойчивость и масштабирование приложений. Поскольку используется все тот же keepalived вместе с ipvs, то я не буду расписывать все подробно и рекомендую обратится к предыдущим статьям 1 и 2.
Цель задачи состоит в замене Windows Network Load Balancing(WNLB) для балансировки соединений к Exchange. Почему не устраивает WNLB?
  1. Не отслеживает доступность сервиса.
  2. Не обеспечивает равномерную балансировку
  3. Повышенная нагрузка на сетевую инфраструктуру
  4. Работает не устойчиво при нагрузке на сервера Exchange.
IP адреса нод кластера балансировки пусть будут 192.168.3.10 и 192.168.3.11. Для минимизации изменений в существующей инфраструктуре наш балансир должен иметь IP ранее принадлежащий WNLB (192.168.3.110). Следовательно, чтобы соединение прошло от клиента к кластеру Exchange (четыре сервера 192.168.3.111 - 192.168.3.114), необходимо осуществить трансляцию адреса назначения - Destination NAT. А чтобы ответные пакеты от Exchange серверов не ушли напрямую к клиенту, нужен Source NAT. Последняя ремарка: в отличие от уже упомянутых статей - это исключительно выделенный кластер для балансировки, который состоит из двух серверов (активный и резервный), в моем случае ОС это OEL6 с ядром UEK R2, это важно, поскольку более старое ядро не позволит реализовать задуманное, т.е. ядро из rhel6 не подойдет.

Итак, конфигурационный файл keepalived:

! Configuration File for keepalived

global_defs {
   notification_email {
      unix_adm@domain.ru
   }
   notification_email_from exchange_balancer01.domain.ru
   smtp_server 192.168.3.1
   smtp_connect_timeout 30
   router_id exchange_balancer01.domain.ru
}

vrrp_instance exchange_relay {
    state MASTER
    interface eth0
    virtual_router_id 117
    priority 100
    lvs_sync_daemon_interface eth0
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mrelay
    }
    virtual_ipaddress {
        192.168.3.110
    }
    preempt
    notify_master "/etc/keepalived/snat.py -a 192.168.3.111 -a 192.168.3.112 -a 192.168.3.113 -a 192.168.3.114 -s 192.168.3.110"
    notify_backup "/etc/keepalived/snat.py -r 192.168.3.111 -r 192.168.3.112 -r 192.168.3.113 -r 192.168.3.114 -s 192.168.3.110"
    notify_fault "/etc/keepalived/snat.py -r 192.168.3.111 -r 192.168.3.112 -r 192.168.3.113 -r 192.168.3.114 -s 192.168.3.110"
}

virtual_server 192.168.3.110 443 {
    delay_loop 20
    lb_algo wlc
    lb_kind NAT
    protocol TCP

    real_server 192.168.3.111 443 {
        weight 1
          MISC_CHECK {
            misc_path "/etc/keepalived/check_exchange.sh 192.168.3.111"
            misc_timeout 18
          }
        }
    
    #Идентичные описания Exchange серверов
}

Что здесь нового:
  • lvs_sync_daemon_interface eth0 - На резервную ноду передается информация об открытых соединениях. Это позволяет оставить рабочими все текущие соединения в случае выхода из строя master ноды. Проверить работоспособность механизма передачи  на резервной ноде можно путем просмотра состояния текущих соединений:
         # ipvsadm -Lnc
  • Скрипт snat.py - в отличие от предыдущих статей, скрипт добавляет правила iptables на активную ноду, чтобы реализовать SNAT, соответственно он же убирает правила на резервной ноде. Правила в виде:
        -A POSTROUTING -d 192.168.3.111/32 -p tcp -j SNAT --to-source 192.168.3.110
  •  lb_kind NAT - Метод передачи пакетов, DNAT.
Чуть подробнее взглянем на скрипт проверки доступности приложения - check_exchange.sh.

#!/bin/sh

error=0
for i in `seq 1 3`
  do
    echo "GET /rpc/healthcheck.htm" | openssl s_client -connect $1:443 -crlf -quiet 2>/dev/null | grep "200 OK" || let error=$error+1
  done
[ $error -lt 3 ] && exit 0 || exit 1

Производится запрос состояния Exchange 2013 Outlook Anywhere путем обращения к странице https://exchange_server/rpc/healthcheck.htm. Если страница содержит 200 OK - состояние рабочее. Скрипт запрашивает три раза, и если хотя бы одна проверка верная, считается что сервис функционирует штатно. Почему так? Сервера exchange, в моем случае, работают под нагрузкой и не всегда успевают выдать страницу проверки. Если есть желание, можете дополнить скрипт на проверку других служб:

owa - Exchange 2013 Outlook Web App
ews - Exchange 2013 Web Services
microsoft-Server-ActiveSync - Exchange 2013 ActiveSync
ecp - Exchange 2013 Control Panel
autodiscover - Exchange 2013 Autodiscover Service
oab - Exchange 2013 Offline Address Book

И последнее, установите переменную ядра:

net.ipv4.vs.conntrack = 1

Без нее не будет работать контроль состояния соединения - это приведет к тому, что правила SNAT и DNAT будут работать не корректно.




воскресенье, 1 марта 2015 г.

Отказоустойчивый, масштабируемый кластер приложения с балансировкой нагрузки, часть 2 (про масштабирование и про ARP Flux)

Возвращаясь к статье Отказоустойчивый, масштабируемый кластер приложения с балансировкой нагрузки, может создаться впечатление, что масштабировать кластер можно, просто добавляя дополнительные ноды. Масштабируемость, на первый взгляд, будет ограничена количеством адресов в сетевом сегменте. Но внимание: чем больше нод, тем больше будет утилизация конечного приложения, и тем больше будет не целевого трафика в сегменте. Этому виной будут перекрестные проверки нод на доступность ресурсов. Следовательно, количество нод, которые могут выполнять функции балансировки, должно быть разумно ограниченным. По моему мнению четыре вполне достаточно. Рассмотрим, как можно преодолеть эту проблему.
Создадите сервер приложения аналогично предыдущим, но keepalived не ставьте. Добавьте интерфейс loopback с общим ip кластера:

# cat /etc/sysconfig/network-scripts/ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.3.100
NETMASK=255.255.255.255
ONBOOT=yes

Не спешите применять настройки. Поговорим вот еще о каком аспекте: по умолчанию linux сервер c несколькими интерфейсами в одной сети будет отвечать на ARP запрос, пришедший на любой локальный интерфейс и содержащий любой целевой локальный ip адрес. Звучит запутанно, покажу на примере: предположим на хосте есть два интерфейса с ip 192.168.3.200 и 192.168.3.201, тогда:

# arping -I eth0 192.168.3.200
ARPING 192.168.3.4 from 192.168.3.102 eth0
Unicast reply from 192.168.3.200 [52:54:00:BD:DF:C2]  1.362ms
Unicast reply from 192.168.3.200 [52:54:00:10:11:35]  1.209ms

Мы получаем два разных ARP ответа, эта проблема называется ARP Flux. Если мы сейчас включим интерфейс lo:0 это, в свою очередь, может стать причиной ARP Poisoning. Для того, чтобы решить эту проблему, необходимо поменять эту модель поведения работы ARP (host based model) на интерфейсо-зависимую (interface based model). Выставите следующие переменные ядра:

# echo -e "net.ipv4.conf.all.arp_ignore = 1 \nnet.ipv4.conf.all.arp_announce = 2" >> /etc/sysctl.d/99-sysctl.conf

Что эти переменные означают:
net.ipv4.conf.all.arp_ignore - определяет различные режимы ответа, на входящие ARP запросы, которые производят разрешение локальных IP адресов. Возможные значения:
  • 0 - установлено по умолчанию. Ответ производится на ARP запрос, пришедший на любой сетевой интерфейс системы, на разрешение любого целевого локального IP адреса.
  • 1 - ответ производится в случае, если ARP запрос на разрешение IP адреса пришел на интерфейс, содержащий этот IP адрес.
  • 2 - ответ производится в случае, если ARP запрос на разрешение IP адреса пришел на интерфейс, содержащий этот IP адрес, причем IP адрес отправителя должен находится в одной подсети целевым IP адресом.
  • 3 - не отвечать, если IP адрес источника находится в той же сети.
  • 4-7 - зарезервированы.
  • 8 - не отвечать на запросы.
net.ipv4.conf.all.arp_announce - определяет, каким образом будет анонсироваться локальный IP адрес в исходящих ARP запросах:
  • 0 - установлено по умолчанию. Используется любой локальный адрес, настроенный на любом интерфейсе.
  • 1 - попытаться исключить локальные адреса, которые не принадлежат к подсети. в которой находится целевой IP адрес. В случае отсутствия такого локального IP адреса будет использоваться поведение за номером 2.
  • 2 - Всегда использовать лучший локальный адрес, с которого нам удобно посылать запрос в целевую подсеть. Такой IP адрес выбирается из первичных IP адресов, находящихся в той же подсети, что и целевой IP адрес, на всех локальных интерфейсах. Если ничего подходящего нет, то будет использован первый ip адрес на интерфейсе, с которого будет произведен запрос или на всех других интерфейсах.
Теперь можно применить изменения и добавить новый сервер приложения в конфигурацию keepalived на всех нодах балансировщиках.