Monday, September 5, 2016

Bucardo: Multi-Master PostgreSQL Cluster!
на примере Zabbix




     Создаем мульти-мастер PostgreSQL кластер на примере двух нод PostgreSQL сервера в FreeBSD Jail's. Кластеризовать будем базу данных Zabbix мониторинга, который будет также жить на двух разных хостах внутри FreeBSD Jail's.
     Итак, разберемся, что у нас что, и зачем мы это делаем...
1. Bucardo - грубо говоря, это скрипт на Perl, реализующий потоковую репликацию между PostgreSQL серверами, и дарящий нам счастливую возможность иметь 48 мастер нод PostgreSQL. Единственная тонкость, что все реплицируемые таблицы должны иметь Primary key, иначе таблицу не удастся включить в кластерную репликацию: Bucardo home site
     Собственно, реализации multi-master репликаций для PostgreSQL без Primary key существуют, например BDR, но он еще не дошел до стабильной стадии, так что пока я его не пробовал. Но в целом, весьма интересная разработка. Когда BDR появится в портах, я его обязательно попробую ;)
2. FreeBSD и Jails - ну а как иначе... Все сервисы должны жить изолированно из соображений безопасности и просто удобства. FreeBSD со своими Jails подходит для этого идеально. Опять же, ZFS пока в нормальном виде только во FreeBSD, в Linux ZFS еще не на такой стадии интеграции, хотя я и на Linux уже активно использую ZFS.
3. Zabbix - его я выбрал чисто для примера. Это не обязательно делать для Zabbix. Вы можете таким образом кластеризовать что угодно! Например можно кластеризовать Asterisk, заставив его хранить экстеншены и все основные настройки в PgSQL. Но и Zabbix, если у вас огромная сеть с кучей устройств для мониторинга,  будет не лишним кластеризовать в multi-master варианте :) Разнеся его по разным серверам и сегментам сети.

     Создаем свой первый jail для PostgreSQL:

     Я использую для управления джейлами QJail. Вполне удобная утилита, "очеловечивающая" работу с джейлами.

     Итак, поехали (все операции выполняются парно на двух серверах!!!):

1. Если джейлы вы раньше не использовали, но у вас есть ZFS, то первым делом перед инициализацией джейлов надо создать датасет для них:

     zfs create -o compression=lz4 system/usr/jails

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

2. Инициализируем jails' при помощи qjail:

     qjail install

3. Создаем датасет для jail с PostgreSQL:

     zfs create system/usr/jails/pgsql0X (pgsql 01 на первой ноде, pgsql02 на второй ноде)

4. А теперь самый важный датасет! Датасет для данных PostgreSQL.

     zfs create -p -o mountpoint=/usr/jails/pgsql0X/usr/local/pgsql -o recordsize=8K system/usr/jails/pgsql0X/pgsql (X=1 для первой ноды и X=2 для второй)

     Параметр recordsize=8K задан для того, что бы размер блока файловой системы и размер блока который пишет PostgreSQL совпадали. PostgreSQL пишет как раз блоками по 8Kb.

5. Создаем Jail:

     qjail create -4 em0|192.168.0.X,lo1|127.0.1.1 pgsql0X (X=1 для первой ноды и X=2 для второй)

     Интерфейс можно использовать основной, к которому у вас подключена локальная сеть, тогда вам не придется ничего больше делать, только открыть доступ в файрволле. Или можно использовать LoopBack - это более секьюрно, но тогда вам потребуется настроить NAT в PF или IPFW, для доступа к джейлу.
     Так же создаем LoopBack для самого джейла, что бы нам было проще взаимодействовать с Bucardo и PostgreSQL: lo1.
     Создать lo1 в системе очень просто, для этого нужно в файл /etc/rc.conf добавить: cloned_interfaces="lo1"
     И сделать: service netif cloneup
     После чего данный интерфейс появится в системе.

6. Джейл создали, теперь идет в /usr/local/etc/qjail.config, ищем там файл с конфигурацией нашего jail (pgsql01 или pgsql02) и вписываем туда параметр "allow.sysvipc;". Без этой опции PostgreSQL не сможет стартовать с ругательствами на невозможность выделения shared memory.

7. После этого запускаем jail:

     qjail start pgsql0X

8. После старта джейла можем действовать двумя путями.Через jexec (это правильнее) или через qjail console (что удобнее на первом этапе):

     jexec pgsql0X pkg update
     jexec pgsql0X pkg install postgresql94-server postgresql94-client postgresql94-plperl p5-Bucardo

9. Если вы планируете несколько PostgreSQL в нескольких джейлах в пределах одного сервера, то нужно перед запуском PgSQL сменить UID его пользователя на другой. UID пользователей pgsql должен различаться во всех джейлах, иначе у вас будут проблемы.

     vipw
     ee /etc/groups

10. После чего переписать права на все, что принадлежало этому юзеру:

     chown -R /usr/local/etc/pgsql

          или

     find / -uid 70 -exec sh -c 'chown pgsql {} \+'
     find / -gid 70 -exec sh -c 'chown :pgsql {} \+'

11. Активируем запуск PostgreSQL и Bucardo:

     sysrc postgresql_enable=YES
     sysrc bucardo_enable=YES (Только на одном из серверов, на втором Bucardo должен быть выключен до тех пор, пока на первой ноде будет работать Bucardo)

12. Далее инициализируем DB:

     service postgresql initdb
   
13. Меняем параметр отвечающий за прослушиваемые интерфейсы в postgresql.conf:

     listen_addresses = '*'

14. Меняем по вкусу pg_hba.conf, но не забываем разрешить полный доступ ко всем базам для пользователя bucardo c IP первого и второго джейлов:
  • # TYPE  DATABASE        USER            ADDRESS                 METHOD
    local   all             all                                     trust
    host    all             all             127.0.1.1/32            trust
    host    all             all             ::1/128                 trust
    host    all             bucardo         127.0.1.1/32            trust
    host    all             bucardo         <ip pg jail 01>/32      trust
    host    all             bucardo         <ip pg jail 02>/32      trust
15. Стартуем PostgreSQL:

      service postgresql start

16. Если PostgreSQL стартовал, подключаемся к нему по адресу LoopBack:

     psql -U pgsql -h 127.0.1.1 postgres

17. Меняем пароль для юзера pgsql и создаем все необходимое для Bucardo:
ALTER USER pgsql WITH PASSWORD 'PASSWORD';
CREATE USER bucardo WITH PASSWORD 'PASSWORD' SUPERUSER;
CREATE DATABASE bucardo WITH OWNER bucardo;
\q
18. Наконец-то переходим к Bucardo:

     Запускаем bucardo install и задаем все нужные параметры:
Current connection settings:
1. Host:           127.0.1.1
2. Port:           5432
3. User:           pgsql
4. Database:       bucardo
5. PID directory:  /var/run/bucardo
Enter a number to change it, P to proceed, or Q to quit: 
19. Жмем 'P' to proceed и все готово! Bucardo наполнит свою базу и можно переходить к конфигурированию Bucardo и базы Zabbix.

20. Создаем юзера и базу для zabbix:
CREATE USER zabbix WITH PASSWORD 'PASSWORD';
CREATE DATABASE zabbix OWNER zabbix;
21. Добавляем в pg_hba.conf записи разрешающие коннект к базе zabbix юзера zabbix из джейлов с заббиксом:
  • host    zabbix          zabbix    <ip zabbix jail 01>/32  md5
    host    zabbix          zabbix    <ip zabbix jail 02>/32  md5
  service postgresql reload

22. Наполняем базы zabbix. *.sql файлы берем из соседнего джейла с zabbix, который вы создали самостоятельно:
cat schema.sql | psql -U zabbix -h <PgSQL.HOST> zabbix
cat images.sql | psql -U zabbix -h <PgSQL.HOST> zabbix
cat data.sql | psql -U zabbix -h <PgSQL.HOST> zabbix
23. И вот тут выплывает мое упоминание про Primary key для всех реплицируемых таблиц... Дело в том, что в схеме заббикса некоторые таблицы не имеют Primary key, и тут нам надо решить, что мы собираемся делать. Тут у нас два варианта:

     A. Сделать, что бы всегда работал только один Zabbix, тогда нам нужно создать primary key для таблиц которые его не имеют:
ALTER TABLE history_uint ADD PRIMARY KEY (itemid,clock);
ALTER TABLE history_str ADD PRIMARY KEY (itemid,clock);
ALTER TABLE history ADD PRIMARY KEY (itemid,clock);
     B. Сделать два работающих мастера Zabbbix, тогда нам нужно исключить таблицы куда пишется статистика и всякое разное заббиксом на основе данных от мониторимых узлов. Вот список этих таблиц:
alerts
escalations
events
history
history_log
history_str
history_text
history_uint
trends
trends_uint

     Итак, конфигурим bucardo! Все что мы делали до этого, мы делали на двух нодах. Теперь же делаем все на первой!

25. Добавляем наши базы в Bucardo:
bucardo add database zabbix_pg01 dbname=zabbix dbhost=127.0.1.1 dbuser=bucardo dbpass=PASSWORD
bucardo add database zabbix_pg02 dbname=zabbix dbhost=<IP pgsql02> dbuser=bucardo dbpass=PASSWORD
bucardo list database
# Database: zabbix_pg01  Status: active  Conn: psql -U bucardo -d zabbix -h 127.0.1.1
# Database: zabbix_pg02  Status: active  Conn: psql -U bucardo -d zabbix -h <ip pgsql02>

25. Создаем группу баз. Source означает, что из этой базы будут браться измененные данные. Если вы напишете target, то в этом случае получите master-slave кластер.
bucardo add dbgroup zabbix_servers zabbix_pg01:source zabbix_pg02:source
# Created dbgroup "zabbix_servers"
# Added database "zabbix_pg01" to dbgroup "zabbix_servers" as source
# Added database "zabbix_pg02" to dbgroup "zabbix_servers" as source
26. Добавляем к репликации все:
bucardo add table all db=zabbix_pg01 relgroup=zabbix_herd
bucardo add sequences all db=zabbix_pg01 relgroup=zabbix_herd
27. А вот теперь, если вы выбрали второй вариант, с двума работающими Zabbix, нужно выкинуть из репликации некоторые таблицы, чтоб избежать конфликтов:

     bucardo remove table public.xxx

     bucardo remove table public.alerts
     bucardo remove table public.escalations
     bucardo remove table public.events
     bucardo remove table public.history
     bucardo remove table public.history_log
     bucardo remove table public.history_str
     bucardo remove table public.history_text
     bucardo remove table public.history_uint
     bucardo remove table public.trends
     bucardo remove table public.trends_uint

И независима от вашего варианта, исключаем базу dbversion, так как она не имеет ключа, и в целом нам не нужна ;)

     bucardo remove table public.dbversion


28. Добавляем теперь собственно синхронизацию:
bucardo add sync zabbix_sync herd=zabbix_herd dbs=zabbix_servers
29. Все, теперь у нас больше не будет конфликтов. Перезапускаем, или просто запускаем Bucardo. Предварительно убедившись, что оба PostgreSQL работают :)

     service bucardo start

30. Смотрим статус Bucardo:
bucardo status zabbix_sync
======================================================================
Last good                       : Aug 31, 2016 19:43:04 (time to run: 1s)
Rows deleted/inserted/conflicts : 1,864 / 1,864 / 1,140
Last bad                        : Aug 31, 2016 19:43:03 (time until fail: 1s)
Sync name                       : zabbix_sync
Current state                   : Good
Source relgroup/database        : zabbix_herd / zabbix_pg01
Tables in sync                  : 105
Status                          : Stalled
Check time                      : None
Overdue time                    : 00:00:00
Expired time                    : 00:00:00
Stayalive/Kidsalive             : Yes / Yes
Rebuild index                   : No
Autokick                        : Yes
Onetimecopy                     : No
Post-copy analyze               : Yes
Last error:                     : 
======================================================================
31. Тестируем! Можно попробовать менять содержимое таблицы users. На одной ноде что-то изменили, тут же поглядели на второй - измениться должно и там. Вот например:

  • Node1 psql -U zabbix -h 127.0.1.1 zabbix:
zabbix=> select userid,alias,surname from users;
 userid | alias |    surname
--------+-------+---------------
      1 | Admin | Administrator
      2 | guest |
(2 rows)

zabbix=> insert into users (userid,alias) values (3,'test');
INSERT 0 1

zabbix=> select userid,alias,surname from users;
 userid | alias |    surname
--------+-------+---------------
      1 | Admin | Administrator
      2 | guest |
      3 | test  |
(3 rows)
  • Node2 psql -U zabbix -h 127.0.1.1 zabbix:
zabbix=> select userid,alias,surname from users;
 userid | alias |    surname
--------+-------+---------------
      1 | Admin | Administrator
      2 | guest |
      3 | test  |
(3 rows)

zabbix=> delete from users where userid=3;
DELETE 1
  • Node1 psql -U zabbix -h 127.0.1.1 zabbix:
zabbix=> select userid,alias,surname from users;
 userid | alias |    surname
--------+-------+---------------
      1 | Admin | Administrator
      2 | guest |
(2 rows)
Все, если вы видели изменения на обеих нодах, то у вас все получилось !;)

Главное, не запускать два Bucardo на двух нодах одновременно! Сделайте, что бы 
Bucardo работал всегда на одной, а на второй (если у вас всего две ноды) он и не нужен будет. Если у вас больше двух нод, придумайте, как поднимать второй в случае падения первой. Я для себя придумал использовать UP/DOWN скрипты на CARP интерфейсе. Если пришел карп на другую ноду, то запускается Bucardo.

     Ну собственно все ;) По-скольку статья про Bucardo и PostgreSQL, то настройка заббикса будет вашим домашним заданием ;) Опишу лишь несколько тонкостей работы:

1. Вносить новые хосты и изменять все что угодно можно на двух заббиксах.
2. Агенты должны коннектиться к двум серверам одновременно, так как статистика не реплицируется, и ее нужно откуда-то брать. В целом это fault-tolerance на уровне приложения, за что zabbix честь и хвала!

Пример конфига zabbix клиента:

     Hostname=server1
     Include=/usr/local/etc/zabbix3/zabbix_agentd.d/
     LogFile=/var/log/zabbix/zabbix_agentd.log
     PidFile=/var/run/zabbix/zabbix_agentd.pid
     Server=zabbix01.example.com,zabbix02.example.com
     ServerActive=zabbix01.example.com,zabbix02.example.com
     LogFileSize=0
     Timeout=30

3. History, events и т.д. не реплицируются, так что конфликтов репликации не будет. Из-за этого на каждом хосте будут видны только свои события. Но это не беда, так как агенты все равно все будут дублировать в оба заббикса ;)

     Ну вот и все тонкости. Не забудьте засунуть zabbix так же в джейлы, а для джейла сделать датасет, только тюнинг датасету под заббикс не нужен.
     В конфиге джейла для zabbix нужно будет включить опцию: allow.raw_sockets = "1";
В целом это негативно сказывается на безопасности, но без нее zabbix не сможет посылать ICMP.

     Обращается каждый заббикс к своему PgSQL. Т.е. у нас получаются эдакие полностью независимые серверы, при этом реплицирующиеся между собой.
     Баланс входящих между двумя заббиксами я бы сделал при помощи двух CARP IP. Один IP мастер на одном сервере, второй на другом. Если один сервер падает, то IP уходит на запасной, и тогда zabbix все равно работает незаметно для пользователя.
     Естественно DNS имя должно ссылаться на оба CARP IP сразу.
     Баланс HTTP трафика можно сделать при помощи двух Nginx с двумя upstreams или при помощи RelayD. Смысл в том, что Nginx либо RelayD имеют два дестинейшена, и даже если CARP не переехал на другой хост, а Zabbix упал, то Nginx поймет это и отфорвардит вас на другой хост. RelayD для этого имеет отличную функцию "check http", которая может не только потыкаться в порт, но и запросить URL, тем самым вы можете проверить одним запросом не только живость HTTP, но и всей системы вместе с БД.

     В целом настройка CARP и RelayD чрезвычайно проста, подробнее о настройке лоад баланса в Nginx можно найти в поисковике, а по RelayD есть отличный пример на сайте: calomel.org

Saturday, January 9, 2016

Строим отказоустойчивую сетевую инфраструктуру предприятия.

Часть 3: Тюнинг настроек пограничных портов и портов доступа на Cisco и HP ProCurve.

Итак, сегодня подготовимся к подведению черты под настройкой нашей сети. Черта эта будет проведена между сетевым оборудованием и пользователями этого оборудования. А точнее, разберемся, что можно сделать, что бы обезопасить нашу STP топологию на портах доступа, а так же на пограничных портах с другими сетями. Начнем с самых базовых настроек, таких как PortFast, BPDUGuard, BPDUFilter и PVST-Filter на ProCurve.

PortFast

     PortFast - этот режим предназначен для того, что бы "ускорить" инициализацию портов которые подключены к серверам или пользовательским станциям. В нормальном состоянии, без PortFast, порт на котором работает Spanning Tree перед включением в режим передачи данных проходит несколько довольно долгих фаз: blocked, listening, learning и только потом, где-то через 40-50 секунд после включения кабеля, он переходит в состояние forwarding и начинает передавать данные. Делается это для того, что бы если на порту окажется дублирующий линк, то Spanning Tree успел бы это понять, и в сети не возникло петли и наша сеть не "сломалась" пусть даже на короткое время. В случае, если на порту находится рабочая станция или сервер, нам не нужно, что бы все включалось с такой осторожностью, даже вернее это вообще может оказаться вредно для работы рабочей станции или сервера, компьютер может например не суметь получить адрес по DHCP, если грузится быстрее, чем инициализируется порт.
     Итак, когда мы включаем PortFast, порт минует состояния listening и learning, и сразу становится forwarding. При включении этого режима, Spanning Tree продолжает работать на этих портах, он не отключается! BPDU принимаются и отправляются. Более того, если на порт в режиме PortFast придёт сообщение BPDU, он моментально потеряет свой статус PortFast не смотря на настройки.  Но тем не менее, не стоит включать PortFast на портах ведущих к другому сетевому оборудованию, так как это все-таки может привести к появлению петель маршрутизации пусть и на короткое время.

Cisco:
     На Cisco этот режим включается двумя способами: локально на конкретных портах либо глобально в режиме конфигурации.
глобально:
spanning-tree portfast default
Эта команда включает PortFast на всех портах которые находятся в режиме access.
локально на портах:
interface GigabitEthernet0/1
spanning-tree portfast
При активной глобальной настройке PortFast его можно отключить на портах где он не нужен:
interface GigabitEthernet0/1
spanning-tree portfast disable

Так же в некоторых случаях может понадобиться включить PortFast на trunk линках, например если данный транк ведёт к серверу, который принимает из него несколько VLAN'ов:
interface GigabitEthernet0/1
spanning-tree portfast trunk

Проверить включен ли PortFast на интерфейса можно при помощи команды:
sh spanning-tree int gi0/1 portfast
MST0                enabled
MST2                enabled

либо:
sh spanning-tree int gi0/1 detail 
 Port 1 (GigabitEthernet0/1) of MST0 is designated forwarding 
   Port path cost 20000, Port priority 128, Port Identifier 128.1.
   Designated root has priority 4096, address 001b.3fc1.a800
   Designated bridge has priority 32768, address 001d.e691.2800
   Designated port id is 128.1, designated path cost 0
   Timers: message age 0, forward delay 0, hold 0
   Number of transitions to forwarding state: 3
   The port is in the portfast mode by default
   Link type is point-to-point by default, Internal
   Bpdu guard is enabled by default
   Loop guard is enabled by default on the port
   BPDU: sent 174100, received 0

 Port 1 (GigabitEthernet0/1) of MST2 is designated forwarding 
   Port path cost 20000, Port priority 128, Port Identifier 128.1.
   Designated root has priority 2, address 0018.71b6.a000
   Designated bridge has priority 32770, address 001d.e691.2800
   Designated port id is 128.1, designated path cost 22000
   Timers: message age 0, forward delay 0, hold 0
   Number of transitions to forwarding state: 2
   The port is in the portfast mode by default
   Link type is point-to-point by default, Internal
   Bpdu guard is enabled by default
   Loop guard is enabled by default on the port
   BPDU: sent 174100, received 0

Тут будет видно, если порт потерял свой статус PortFast, для возвращения порту статуса PortFast нужно его положить и поднять:
interface GigabitEthernet0/1
shutdown
no shutdown

HP ProCurve:
     На ProCurve это называется edge-port, и насильно включается командой admin-edge-port для каждого порта, но по-умолчанию глобально работает функция auto-edge-port, которая сама определят, нужно на этом порту инициализироваться "по-быстрому" или нужно идти по полному циклу. И надо отметить, что на HP эта автоматическая функция работает очень хорошо! Порты без всякого тюнинга инициализируются быстро там, где стоят рабочие станции и сами переходят в EDGE режим, и так же теряют EDGE статус даже при активном admin-edge-port, если на порт приходят сообщение BPDU снаружи.

Включается это так:
spanning-tree A1-A2 admin-edge-port

В sh run это будет выглядеть так:
spanning-tree A1 admin-edge-port
spanning-tree A2 admin-edge-port

И можно насильно отключить авто определение EDGE порта, что бы он всегда инициализировался по долгому и безопасному сценарию:
no spanning-tree A1-A2 auto-edge-port

В sh run это будет выглядеть так:
no spanning-tree A1 auto-edge-port
no spanning-tree A2 auto-edge-port

Вернуть статус auto-edge-port и отключить admin-edge-port можно командами:
spanning-tree A1-A2 auto-edge-port
и
no spanning-tree A1-A2 admin-edge-port

Проверить статус порта можно при помощи команд:
sh spanning-tree A1
  Port   Type       | Cost      rity State        | Bridge        Time PtP Edge
  ------ ---------- + --------- ---- ------------ + ------------- ---- --- ----
  A1     100/1000T  | 20000     128  Forwarding   | 001b3f-582100 2    Yes No  

либо
sh spanning-tree A1 detail
  AdminEdgePort             : No 
  Auto Edge Port            : Yes         
  OperEdgePort              : No


BPDUFilter

     Эта функция отключает прием и передачу BPDU на конкретных портах. Это может применяться для разных целей, например для защиты от "чужого" Spanning Tree на линках к провайдеру или к иным соседям, с которыми у вас гарантировано один линк. Для защиты от атак на основе BPDU и как следствие, нестабильность работы вашей топологии.

Cisco:
     На Cisco BPDUFilter как и PortFast включается двумя способами: локально на интерфейсе и глобально. Но в отличие от PortFast, у BPDUFilter от способа включения меняется поведение.
Локально:
interface GigabitEthernet 0/1
spanning-tree bpdufilter enable / disable
Как и в случае Portfast, disable отключает глобальную настройка для конкретного порта.
Глобально (автоматически включает BPDUFilter на всех PortFast интерфейсах):
spanning-tree portfast bpdufilter default

     При локальном включении BPDUFilter работает как "стена", это равносильно отключению Spanning Tree на интерфейсе вообще. Никакие BPDU не проходят ни в одну сторону. В некоторых случаях это может быть опасно, например соединив случайно такой порт с соседним вы получите петлю, которую не устранит Spanning Tree, и если у вас не настроено других средств борьбы с петлями, то у вас рухнет сеть. Так что будьте внимательны и осторожны использую эту функцию локально на интерфейсе.
     При глобальном включении этой функции, она не настолько опасна, потому что включается на PortFast портах, и блокирует только отправку BPDU, а не приём. И как и PortFast, глобальный BPDUFilter снимается с порта при приёме первого же BPDU пакета снаружи. Эта функция используется скорее для маскировки вашего BPDU от соседей, но в случае если от соседей придёт BPDU, то вы начнете с ними работать по Spanning Tree.

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

Узнать включен ли у вас BPDUFilter глобально:
sh spanning-tree summary 
Switch is in mst mode (IEEE Standard)
Root bridge for: none
Extended system ID           is enabled
Portfast Default             is enabled
PortFast BPDU Guard Default  is enabled
Portfast BPDU Filter Default is disabled
Loopguard Default            is enabled
EtherChannel misconfig guard is enabled
UplinkFast                   is disabled
BackboneFast                 is disabled

Узнать активен ли он на порту:
sh spanning-tree int gi0/1 detail 
 Port 1 (GigabitEthernet0/1) of MST0 is designated forwarding 
   Port path cost 20000, Port priority 128, Port Identifier 128.1.
   Designated root has priority 4096, address 001b.3fc1.a800
   Designated bridge has priority 32768, address 001d.e691.2800
   Designated port id is 128.1, designated path cost 0
   Timers: message age 0, forward delay 0, hold 0
   Number of transitions to forwarding state: 3
   The port is in the portfast mode by default
   Link type is point-to-point by default, Internal
   Bpdu guard is enabled by default
   Bpdu filter is enabled
   Loop guard is enabled by default on the port
   BPDU: sent 174100, received 0

 Port 1 (GigabitEthernet0/1) of MST2 is designated forwarding 
   Port path cost 20000, Port priority 128, Port Identifier 128.1.
   Designated root has priority 2, address 0018.71b6.a000
   Designated bridge has priority 32770, address 001d.e691.2800
   Designated port id is 128.1, designated path cost 22000
   Timers: message age 0, forward delay 0, hold 0
   Number of transitions to forwarding state: 2
   The port is in the portfast mode by default
   Link type is point-to-point by default, Internal
   Bpdu guard is enabled by default
   Bpdu filter is enabled
   Loop guard is enabled by default on the port
   BPDU: sent 174100, received 0

Если BPDUFilter не включен, то этой строки не будет вообще.

HP ProCurve:
     На ProCurve BPDUFilter включается для каждого порта:
spanning-tree A1-A2 bpdu-filter
В su run это будет выглядеть так:
spanning-tree A1 loop-guard bpdu-filter
spanning-tree A2 loop-guard bpdu-filter

Узнать список портов с включенным BPDUFilter:
sh spanning-tree | i Filter
 BPDU Filtered Ports  : A1-A2

либо:
sh spanning-tree A1 detail 
  BPDU Filtering            : Yes

Так же на HP есть еще одна хорошая функция, которая полезна в случае использования MSTP, и описанного мной в Часть 2: "Соединяем Cisco и ProCurve при помощи MSTP" случая, когда Cisco сходила с ума от приёма PVST пролетавшего сквозь топологию ProCurve.

PVST-FilterВключается так же, как и BPDUFilter:
spanning-tree A1-A2 pvst-filter

В sh run выглядит так:
spanning-tree A1 pvst-filter
spanning-tree A2 pvst-filter

посмотреть статус PVST-Filter:
sh spanning-tree | i PVST
  PVST Filtered Ports  : A1-A2

либо:
sh spanning-tree a1 det
  PVST Filtering            : Yes

     Возможно, если вы используете MSTP, эту функцию стоит активировать на всех портах, так как ничего хорошего от приёма чужого PVST не будет. Как минимум MSTP и PVST несовместимы, а как максимум может произойти крах всей сети, похуже описанного мной случая в  Часть 2: "Соединяем Cisco и ProCurve при помощи MSTP"...

BPDUGuard

     На Cisco BPDUGuard включается локально на интерфейсе и глобально. Ведет себя он независимо от способа включения, абсолютно одинаково. При приёме входящего BPDU на порту с активированным BPDUGuard, порт просто блокируется.

Cisco:
Локально:
interface GigabitEthernet 0/1
spanning-tree bpduguard enable / disable
Как и в случае Portfast, disable отключает глобальную настройка для конкретного порта.
Глобально (автоматически включает BPDUGuard на всех PortFast интерфейсах):
spanning-tree portfast bpduguard default

При блокировке порта восстановить его работоспособность можно выключением и включением:
interface GigabitEthernet0/1
shutdown
no shutdown

Либо настроив автоматическое включение при помощи механизма errdisable recovery:
errdisable recovery cause bpduguard
errdisable recovery interval 60

Включен ли BPDUGuard глобально:
sh spanning-tree summary 
PortFast BPDU Guard Default  is enabled

Узнать активен ли он на порту:
sh spanning-tree int gi0/1 detail 
 Port 1 (GigabitEthernet0/1) of MST0 is designated forwarding 
   Port path cost 20000, Port priority 128, Port Identifier 128.1.
   Designated root has priority 4096, address 001b.3fc1.a800
   Designated bridge has priority 32768, address 001d.e691.2800
   Designated port id is 128.1, designated path cost 0
   Timers: message age 0, forward delay 0, hold 0
   Number of transitions to forwarding state: 3
   The port is in the portfast mode by default
   Link type is point-to-point by default, Internal
   Bpdu guard is enabled by default
   Loop guard is enabled by default on the port
   BPDU: sent 174100, received 0

 Port 1 (GigabitEthernet0/1) of MST2 is designated forwarding 
   Port path cost 20000, Port priority 128, Port Identifier 128.1.
   Designated root has priority 2, address 0018.71b6.a000
   Designated bridge has priority 32770, address 001d.e691.2800
   Designated port id is 128.1, designated path cost 22000
   Timers: message age 0, forward delay 0, hold 0
   Number of transitions to forwarding state: 2
   The port is in the portfast mode by default
   Link type is point-to-point by default, Internal
   Bpdu guard is enabled by default
   Loop guard is enabled by default on the port
   BPDU: sent 174100, received 0

HP Procurve:
На ProCurve он включается и мониторится абсолютно аналогично BPDU-Filter и PVST-Filter, но называется BPDU-Protection:

spanning-tree A1-A2 bpdu-protection

В sh run будет так:
spanning-tree A1 loop-guard bpdu-protection
spanning-tree A2 loop-guard bpdu-protection

Статус BPDU-Protection:
sh spanning-tree | i Protect
  BPDU Protected Ports : A1-A16,A18-A24,B1-B24,C1-C24,D1-D24,G...

sh spanning-tree a1 detail | i Protect
  BPDU Protection           : Yes

На мой взгляд BPDUGuard черезвычайно полезная штука, так как позволяет узнать, когда в порт несанкционированно воткнули сетевое оборудование, а так же BPDUGuard моментально спасает от большинства петель. Но с BPDUGuard можно поймать и проблемы, например активировав его на интерфейсе который смотрит к провайдеру. От провайдеров, по моему опыту, частенько прилетает STP, что моментально приведёт к блокировке порта. Я, конечно весьма осмотрительно, но на интерфейсах к провайдерам с которыми у нас нет дополнительных линков, обычно включаю BPDUFIlter :)


     В следующий раз добавлю про loop-guard, loop-protect, udld и дополнительно скомпоную в одну статью все что связано с борьбой против петель на управляемом и неуправляемом оборудовании. На этом закончим со Spanning Tree и петлями и пойдём дальше к резервированию каналов доступа и кластерам :)

Saturday, January 2, 2016

UnixDaemonReloader - обновление от 2016.01.03



     Обновилась версия программы. Добавились такие функции:

  1. Задержка перед выполнением перезапуска, после изменения файла;
  2. Возможность выполнения перед основным скриптом перезапуска, предварительного скрипта на пример с проверкой консистентности конфига или иных действий, и уже на основе возвращенного ответа от предварительного скрипта начинать перезапуск, или запускать скрипт с реакцией на ошибку. Все эти параметры опциональны, и не обязательны к использованию.


Конфигурацияонный файл:














Обновление от 2016.01.03: 
     Добавлены параметры "скрипт предварительной проверки", "результат удачной проверки" и "скрипт в случае ошибки проверки" в список файлов для отслеживания в кофигурационном файле. Скрипт предварительной проверки должен возвращать результат проверки на стандартный вывод. Например: "OK". Если Возвращенное текстовое значение равно тому что в конфиге - выполняется скрипт перезапуска, иначе после окончания попыток проверки исполнится скрипт ошибки. Смотри README.md для ознакомления с новым синтаксисом.
     PS: Вы можете добавить в скрипт предварительной проверки например проверку конфига на правильность или бекап конфига. В скрипт ошибки тоже можно добавить отправку E-Mail, SMS или возврат копии конфига из бэкапа.
     Добавлен параметр UDR_ScriptsPath, указывающий путь к предварительным скриптам.
     Добавлен параметр UDR_PreAppAttempt, указывающий количество попыток исполнения скрипта предварительной проверки, поселе чего исполняется скрипт обработки ошибки или попытки прекращаются.
     Исправлен тотальный перезапуск всего и вся после первого создания базы файлов.
Обновление от 2015.12.23: 
UDR_PauseBefore - пауза в секундах перед запуском скрипта. Этот параметр сделан для того, что бы если вы вдруг случайно во время редактирования конфига сохранили файл "недоделанным", то у вас было время на исправление ошибки до перезапуска демона.
Полное описание конфигурационного файла в: Полная статья про Unix Daemon Reloader

     Исходники:
          UnixDaemonReloader Source Code

     Скомпилированные версии для FreeBSD и Linux:
          UnixDaemonReloader on SourceForge
          UnixDaemonReloader on My Google Drive