воскресенье, 30 апреля 2017 г.

Контроль программного RAID-массива Linux через Zabbix

Статья про контроль с помощью Zabbix программных RAID-массивов Linux, созданных средствами mdadm. На этот раз кроме установленного и настроенного в системе Zabbix-агента не понадобится более никаких дополнительных пакетов.

Первое решение, приходящее на ум - использовать программу mdadm. Но есть решение получше - использовать для этого файл /proc/mdstat. Для этого можно вписать в файл конфигурации Zabbix-агента /etc/zabbix/zabbix_agentd.conf всего одну строчку:
UserParameter=raid,egrep -c '_U|U_' /proc/mdstat
В этом файле состояние RAID-массивов отображается в виде символов между двумя квадратными скобками. Символ U соответствует исправному диску, символ подчёркивания соответствует неисправному диску. Команда egrep считает количество строчек, в которых символ U соседствует с символом подчёркивания. Предполагается, что в массиве есть как минимум два диска и один из них всегда исправен.

Но однажды мне понадобилось поставить на контроль систему, в которой были настроены массивы RAID-50 и сделано это было так: сначала из дисков собиралось несколько массивов RAID-5, а уже из этих RAID-массивов собирался массив RAID-0. Выглядит это вот так:
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4]
[raid10]
md0 : active raid0 md3[2] md2[1] md1[0] md4[3]
93765249024 blocks super 1.2 512k chunks

md4 : active raid5 sdw1[0] sdab1[5] sdz1[3] sdx1[1] sdaa1[4] sdac1[7] sdy1[2]
23441312640 blocks super 1.2 level 5, 64k chunk, algorithm 2 [7/7] [UUUUUUU]
bitmap: 1/15 pages [4KB], 131072KB chunk

md2 : active raid5 sdk1[2] sdi1[0] sdl1[3] sdn1[5] sdj1[1] sdm1[4] sdo1[7]
23441312640 blocks super 1.2 level 5, 64k chunk, algorithm 2 [7/7] [UUUUUUU]
bitmap: 1/15 pages [4KB], 131072KB chunk

md3 : active raid5 sdq1[1] sds1[3] sdp1[0] sdt1[4] sdu1[5] sdv1[7] sdr1[2]
23441312640 blocks super 1.2 level 5, 64k chunk, algorithm 2 [7/7] [UUUUUUU]
bitmap: 2/15 pages [8KB], 131072KB chunk

md1 : active raid5 sdc1[1] sdb1[0] sde1[3] sdd1[2] sdf1[4] sdg1[5] sdh1[7]
23441312640 blocks super 1.2 level 5, 64k chunk, algorithm 2 [7/7] [UUUUUUU]
bitmap: 1/15 pages [4KB], 131072KB chunk

unused devices: <none>
В случае объединения дисков в режиме LINEAR можно наблюдать такую же картину, что и в случае RAID-0:
$ cat /proc/mdstat
Personalities : [linear]
md0 : active linear sdb[0] sde[3] sdd[2] sdc[1]
15628074304 blocks super 1.2 0k rounding

unused devices: <none>
По идее, хорошо бы контролировать деградацию массивов RAID-0 и LINEAR, но описанный выше способ контроля для них не применим.

Поиски способов контроля вывели на файловую систему /sys. На русском языке лучшим материалом на интересующую нас тему является статья Виктора Вислобокова: Недокументированные фишки программного RAID в Linux.

В итоге сформировался новый вариант строчки для файла конфигурации Zabbix-агента /etc/zabbix/zabbix_agentd.conf:
UserParameter=raid,fgrep -L in_sync /sys/block/md*/md/dev-*/state | wc -l
Этот вариант, правда, тоже может таить в себе неожиданности. У меня есть подозрения, что если в системе заготовлен запасной диск, который включён в один из RAID-массивов в таковом качестве, то в его файле состояния будет строчка spare. Если это действительно так, то это состояние нормальное и не должно приводить к срабатыванию триггера. Однако, системы с запасным диском мне не попадались и проверить свои подозрения мне было негде, поэтому я решил оставить всё как есть - все состояния отличные от in_sync будут считаться аварийными. Если мне попадётся в будущем такая система, то можно будет переделать контроль соответствующим образом, чтобы состояние spare не считалось аварийным.

После внесения изменений в конфигурацию Zabbix-агента, не забудьте его перезапустить:
# /etc/init.d/zabbix-agent restart
Я подготовил два шаблона для контроля параметров исправности RAID-массивов:
В шаблоне есть всего один элемент данных, контролирующий количество неисправных элементов RAID-массивов:

И всего один триггер, который срабатывает при наличии хотя бы одного неисправного элемента хотя бы одного RAID-массива:

воскресенье, 23 апреля 2017 г.

Контроль длины очереди отложенных писем Postfix через Zabbix

В прошлом я писал статьи о настройке Postfix для пересылки сообщений для администратора через полноценный почтовый сервер:
Когда таких серверов становится много, а некоторые из них рассылают большое количество писем, становится трудно своевременно обнаруживать проблемы с отправкой писем. Помочь в таком случае может система мониторинга. При проблемах с отправкой писем почтовый сервер откладывает проблемные письма в отдельную очередь, чтобы через некоторое время попробовать отправить эти письма снова. В Postfix эта очередь отложенных писем называется deferred. Для контроля количества писем в этой очереди нам понадобится настроенный Zabbix-агент и установленный пакет sudo. Настройку Zabbix-агента и установку sudo не описываю в виду их тривиальности.

При помощи команды visudo разрешим пользователям из группы zabbix выполнять от имени пользователя root команду поиска файлов в очереди Postfix:
%zabbix    ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix/deferred -type f
В файл конфигурации Zabbix-агента /etc/zabbix/zabbix_agentd.conf (или /usr/local/etc/zabbix24/zabbix_agentd.conf для случая FreeBSD с Zabbix-агентом версии 2.4) пропишем пользовательский параметр, который будет выполнять команду, подсчитывающую количество файлов, найденных в очереди отложенных писем Postfix:
UserParameter=postfix.deferred.length,sudo /usr/bin/find /var/spool/postfix/deferred -type f | wc -l
После внесения изменений в конфигурацию Zabbix-агента, не забудьте его перезапустить:
# /etc/init.d/zabbix-agent restart
В шаблоне есть:
  • один элемент данных с ключом postfix.deferred.length, с помощью которого раз в 5 минут контролируется количество писем в очереди отложенных,
  • один макрос {$POSTFIX_DEFERRED_LIMIT} со значением 200, который задаёт порог срабатывания триггера,
  • один триггер "Проблемы с отправкой почты", который срабатывает, если в очереди скопилось больше писем, чем указано в макросе.
Вот как выглядят соответствующие вкладки шаблона:



Вот наиболее интересный фрагмент графика с одного из серверов:

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

воскресенье, 16 апреля 2017 г.

Установка Debian с флешки по SSH

Когда возникает задача настроить сервер для другого города, часто задача решается одним из способов:
  1. Сервер отправляется в филиал полностью преднастроенным, так что местным системным администраторам остаётся только установить его в стойку и подключить к сети,
  2. Один из системных администраторов из головного офиса компании отправляется в командировку в филиал, где и настраивает сервер вместе с местными системными администраторами,
  3. Местные системные администраторы сами устанавливают на имеющееся оборудование операционную систему и настраивают на сервере сеть, после чего настройку сервера продолжают системные администраторы из головного офиса.
Последний способ позволяет обойтись без расходов на транспорт - не нужно платить за перевозку преднастроенного сервера, не нужно оплачивать командировочные расходы. Однако и у этого способа имеются свои недостатки - иногда на этапе установки операционной системы бывает нужно выполнить сложную разметку дисков или подгрузить дополнительные драйверы. В подобных случаях лучшим решением может быть использование устройства IP-KVM, если оно есть в филиале. Если же такого устройства в филиале нет, то сгодиться могут разнообразные суррогаты. Один из таких суррогатов и будет рассмотрен в этой статье. Мы подготовим образ флэш-карты с инсталлятором операционной системы Debian, консоль которого после загрузки будет доступна по SSH.

Чтобы подготовить загрузочный образ, необходима уже установленная система Debian. Установим пакет debian-installer, необходимые для его сборки зависимости и пакет fakeroot:
# apt-get source debian-installer
# apt-get build-dep debian-installer
# apt-get install fakeroot
В текущем каталоге будет создан каталог с исходными текстами пакета debian-installer. Перейдём в этот каталог:
# cd debian-installer-20130613+deb7u3/
Откроем в редакторе файл build/pkg-lists/base и добавим в него одну строчку:
#include "network-console"
Эта строчка добавит в инсталлятор дополнительные пакеты, которые сделают возможным доступ к загруженному инсталлятору по SSH.

Создадим файл preseed.cfg и пропишем в него ответы на первые вопросы инсталлятора:
# Выбираем локаль и раскладку клавиатуры
d-i localechooser/shortlist select RU
d-i keyboard-configuration/xkb-keymap select ru
# Задаём настройки сетевой карты
d-i netcfg/enable boolean true
d-i netcfg/choose_interface select eth0
d-i netcfg/disable_autoconfig boolean true
d-i netcfg/get_ipaddress string 192.168.1.16
d-i netcfg/get_netmask string 255.255.255.0
d-i netcfg/get_gateway string 192.168.1.1
d-i netcfg/get_nameservers string 192.168.1.2 192.168.1.3
d-i netcfg/confirm_static boolean true
# Задаём имя сервера и домен
d-i netcfg/get_hostname string server
d-i netcfg/get_domain string core.ufanet.ru
# Включаем доступ к инсталлятору по SSH с логином installer и паролем installer-password
d-i anna/choose_modules string network-console
d-i preseed/early_command string anna-install network-console
d-i network-console/password password installer-password
d-i network-console/password-again password installer-password
# Подключаем сетевой репозиторий для скачивания недостающих пакетов
d-i mirror/country string manual
d-i mirror/http/hostname string mirror.ufanet.ru
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
d-i mirror/suite string wheezy
d-i mirror/udeb/suite string wheezy
В этом файле можно сразу указать сетевые настройки будущего сервера, согласовав их с системными администраторами филилала. А можно договориться использовать одни и те же сетевые настройки только на период настройки новых серверов, после чего на готовом сервере менять настройки на постоянные.

Теперь отредактируем build/config/local и добавим в него полное имя файла preseed.cfg и кодовое имя релиза инсталлятора:
PRESEED=/root/preseed.cfg
USE_UDEBS_FROM=wheezy
Осталось только собрать образ загрузочного диска с инсталлятором. Для этого нужно перейти в каталог build и выполнить команду сборки образа:
# cd build
# fakeroot make rebuild_monolithic
Эта команда соберёт образ "small bootable CD image for network install" - "маленький загрузочный образ компакт-диска для сетевой установки". Такой образ содержит полный комплект пакетов самого инсталлятора, но устанавливаемые пакеты будет скачивать по сети.

Собранный образ можно найти в файле dest/netboot/mini.iso Остаётся только отправить этот образ системным администраторам филиала, например, по электронной почте. Дальше системные администраторы филиала должны будут записать этот образ на свободную флэшку и загрузить с неё будущий сервер. Дальнейший процесс разметки дисков, настройки учётных записей, настройки системных часов, часового пояса можно производить через SSH из головного офиса, зайдя по SSH с логином installer и указав пароль из файла preseed.cfg (в примере выше это пароль installer-password).

Полный список вариантов образов можно узнать, выполнив команду fakeroot make без указания конкретной цели сборки. Среди других вариантов для наших целей полезными могут оказаться:
  • rebuild_netboot - "tiny CD image that boots the netboot installer" - "крошечный образ компакт-диска, который загрузит установщик с сетевой загрузкой". Образ получится самым маленьким, т.к. недостающие пакеты инсталлятора будут загружаться по сети. Собранный образ можно найти в файле dest/monolithic/mini.iso,
  • rebuild_hd-media - "1 gb image (compressed) for USB memory stick" - "сжатый образ размером в 1 гигабайт для флэш-карт". Этот образ содержит в себе полный комплект пакетов инсталлятора и самые популярные устанавливаемые пакеты операционной системы. Собранный образ можно найти в файле dest/hd-media/boot.img.gz
При создании файла preseed.cfg можно ориентироваться на официальный пример файла wheezy/example-preseed.txt или брать значения опций из уже установленной где-либо системы. Для этого нужно установить в этой системе пакет debconf-utils:
# apt-get install debconf-utils
Вывести на экран значения настроек можно при помощи такой команды:
# debconf-get-selections --install
Вместо указания настроек mirror в файле preseed.cfg можно создать файл со списком репозиториев - build/sources.list.udeb.local. Например, вот такой:
deb http://mirror.ufanet.ru/debian wheezy main contrib non-free
deb http://mirror.ufanet.ru/debian wheezy-updates main contrib non-free
deb http://mirror.ufanet.ru/debian wheezy-proposed-updates main contrib non-free
deb http://mirror.ufanet.ru/debian-security wheezy/updates main contrib non-free
Использованные материалы:

воскресенье, 9 апреля 2017 г.

Решение проблемы с паразитным трафиком TCP ACK

Столкнулся с необычной проблемой. Имеется Zabbix-сервер, работающий под управлением FreeBSD, и Zabbix-прокси, работающий под управлением Linux. Между ними находится NAT-шлюз, работающий под управлением FreeBSD. В такой конфигурации Zabbix-сервер и Zabbix-прокси периодически начинают забрасывать друг друга огромным количеством пустых пакетов с флагом ACK:
09:59:13.868487 IP x.y.z.4.60272 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 3255861608], length 0
09:59:13.868496 IP x.y.z.8.10054 > x.y.z.4.60272: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.868498 IP x.y.z.4.53217 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 738884814], length 0
09:59:13.868504 IP x.y.z.8.10054 > x.y.z.4.53217: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.868990 IP x.y.z.4.60272 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 3255861608], length 0
09:59:13.868997 IP x.y.z.8.10054 > x.y.z.4.60272: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.868999 IP x.y.z.4.53217 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 738884814], length 0
09:59:13.869005 IP x.y.z.8.10054 > x.y.z.4.53217: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.869364 IP x.y.z.4.60272 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 3255861608], length 0
09:59:13.869372 IP x.y.z.8.10054 > x.y.z.4.60272: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.869374 IP x.y.z.4.53217 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 738884814], length 0
09:59:13.869380 IP x.y.z.8.10054 > x.y.z.4.53217: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.869863 IP x.y.z.4.60272 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 3255861608], length 0
09:59:13.869870 IP x.y.z.8.10054 > x.y.z.4.60272: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.869872 IP x.y.z.4.53217 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 738884814], length 0
09:59:13.869878 IP x.y.z.8.10054 > x.y.z.4.53217: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.870238 IP x.y.z.4.60272 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 3255861608], length 0
09:59:13.870245 IP x.y.z.8.10054 > x.y.z.4.60272: Flags [.], ack 4294967295, win 65535, length 0
09:59:13.870247 IP x.y.z.4.53217 > x.y.z.8.10054: Flags [.], ack 1, win 457, options [nop,nop,TS val 200464 ecr 738884814], length 0
09:59:13.870253 IP x.y.z.8.10054 > x.y.z.4.53217: Flags [.], ack 4294967295, win 65535, length 0
Тут видно два подключения с портов 60272 и 53217 на порт 10054. Интервалы времени между ответными пакетами составляют единицы микросекунд. В результате образуется взаимный шторм в десятки тысяч пакетов в секунду. Самое интересное, что остановка Zabbix-прокси не приводит к пропаданию этого трафика - пакеты продолжают сыпаться.

Имеется аналогичная конфигурация, в которой Zabbix-сервер работает под управлением Linux. То есть два Linux'а разделены NAT-шлюзом под управлением FreeBSD. В этой конфигурации подобной проблемы не наблюдается.

Как я выяснил, Zabbix тут вообще не при чём. Я нашёл описание заплатки для Linux, в которой описана эта проблема: Merge branch 'tcp_ack_loops'. Проблема проявляется, когда промежуточный шлюз вносит изменения в параметры TCP-подключения этих двух узлов - меняет номер последовательности, номер ACK или отметку времени. Один из узлов, получив такой пакет, сообщает противоположной стороне о несовпадении параметров установленного подключения, отправляя ей пакет ACK. Другая сторона получает этот пакет ACK, а параметры в нём тоже не совпадают с параметрами установленного подключения. Обе стороны начинают забрасывать друг друга ACK-пакетами, в которых сообщается, что противная сторона отправила пакет с параметрами, отличающимися от параметров установленного соединения.

В новых версиях ядра Linux должна появиться переменная net.ipv4.tcp_invalid_ratelimit, описание которой можно найти здесь - /proc/sys/net/ipv4/* Variables. Приведу перевод описания этой переменной ядра:
tcp_invalid_ratelimit - ЦЕЛОЕ

Ограничивает максимальную скорость отправки дубликатов подтверждений в ответ на входящие пакеты TCP, которые соответствуют существующему подключению, но по одной из причин считаются неправильными:
  1. номер последовательности за пределами окна,
  2. номер подтверждения за пределами окна, или
  3. ошибка проверки PAWS (Protection Against Wrapped Sequence numbers - защита от завёрнутых номеров последовательности).
Может помочь смягчить простые DoS-атаки "цикл ACK", когда неисправный хост или злоумышленник между ними может переписать поля заголовка TCP таким образом, что это заставит каждую из сторон считать, что другая отправляет неисправные сегменты TCP, что заставит каждую из сторон отправлять непрекращающийся поток дубликатов подтверждений о неисправных сегментах.

Значение 0 отключит ограничение скорости дубликатов подтверждений в ответ на неисправные сегменты; в противном случае значение указывает минимальный интервал между отправкой дубликатов подтверждений в миллисекундах.

Значение по умолчанию: 500 миллисекунд.
Обновлять ядро Linux мне не хотелось, т.к. в конфигурации Linux-FreeBSD-Linux всё работало нормально и без этой заплатки. Я стал искать обходные решения.

На правильное направление меня вывела вот эта статья - FreeBSD Tuning and Optimization. Приведу перевод фрагмента, описывающего возможные проблемы от включения функции Syncookies:
Syncookies обладают как плюсами, так и минусами. Syncookies полезны если вы находитесь под DoS-атакой, поскольку с их помощью можно отличать настоящих клиентов от компьютеров злоумышленников. Но, поскольку опции TCP из начального SYN-пакета не сохраняются в Syncookies, опции TCP не применяются к подключению, препятствуя использованию функций масштабирования окна, отметок времени или точному определению размера MSS. Поскольку при получении ответного ACK устанавливаетcя подключение, злоумышленник может попробовать наводнить машину пакетами ACK, чтобы попытаться создать подключение.

Дополнительно для переполнения получателя настоящих SYN-куки злоумышленник может добавить к пакету данные. Тогда злоумышленник сможет отправлять данные сетевому демону FreeBSD, даже используя поддельный IP-адрес отправителя. Это приведёт к тому, что FreeBSD будет обрабатывать данные, которые не обрабатывались бы, если бы Syncookies были выключены. Несмотря на то, что Syncookies полезны во время DoS-атак, мы собираемся отключить синкуки.
Я попробовал выключить на Zabbix-сервере под управлением FreeBSD использование опции Syncookies:
# sysctl -w net.inet.tcp.syncookies=0
Затем на время заблокировал на время исходящий трафик на Zabbix-прокси, работающем под управлением Linux:
# iptables -A OUTPUT -d x.y.z.8 -p tcp -m tcp --dport 10054 -j DROP
Выждав полминуты, снова его разблокировал:
# iptables -D OUTPUT -d x.y.z.8 -p tcp -m tcp --dport 10054 -j DROP
В результате паразитный трафик пропал.

То есть, как я понял, изменения, вносимые в TCP-пакеты промежуточным шлюзом, осуществляющим трансляцию адресов, могут приводить к тому, что обе стороны будут слать друг другу ACK-пакеты с несовпадающими параметрами. Эти ACK-пакеты сервером FreeBSD будут восприниматься как пакеты, продолжающие процесс установки нового подключения - FreeBSD посчитает, что отправитель ACK-пакета ранее отправлял ей SYN-пакет и уже получил в ответ подтверждение в виде SYN-ACK-пакета. Таким образом FreeBSD создаст новое подключение. В дальнейшем обе стороны будут обмениваться друг с другом сообщениями о получении пакета, не соответствующего тем параметрам подключения, которые обе стороны согласовали друг с другом ранее. Не претендую на полное понимание ситуации и точность объяснения, но отключение Syncookies на стороне Zabbix-сервера под управлением FreeBSD помогло избавиться от проблемы.

Чтобы Syncookies отключались после перезагрузки системы, нужно внести соответствующие настройки в файл /etc/sysctl.conf:
net.inet.tcp.syncookies=0

воскресенье, 2 апреля 2017 г.

Решение проблемы с остановкой загрузки из-за RAID-контроллера Intel RS2WC040

Столкнулся с проблемой - один из серверов не загружался после аварийного отключения питания. К сожалению, снимки экрана в процессе загрузки не сохранились, поэтому я сейчас не могу сказать, что натолкнуло меня на мысль о том, что причина заключается в RAID-контроллере. Решил сравнить при помощи diff настройки контроллеров на проблемном сервере и на сервере, где такой проблемы не наблюдается. Для этого вывел настройки RAID-контроллеров при помощи такой команды:
# megacli -AdpAllInfo -aALL
Глаз зацепился только за одно различие, которое можно причислить собственно к настройкам контроллеров, а не к их свойствам:
< BIOS Error Handling            : Pause on Errors
---
> BIOS Error Handling            : Stop On Errors
Поискал в интернете и нашёл статью How to disable LSI MegaRAID SAS controller’s suspend boot on error “feature”

Посмотреть текущее значение этой настройки можно следующей командой:
# MegaCli -AdpBIOS -Dsply -aALL
На проблемном сервере эта команда выдавала следующее:
BIOS on Adapter 0 is Enabled.
    BIOS will Bypass error.
Auto select Boot on Adapter 0 is Disabled.

Exit Code: 0x00
На сервере без проблем эта команда выдавала следующее:
BIOS on Adapter 0 is Enabled.
    BIOS will Stop on error.
Auto select Boot on Adapter 0 is Disabled.

Exit Code: 0x00
Выставить значение Stop on error можно следующей командой:
# MegaCli -AdpBIOS -SOE -aALL
При последующих перезагрузках сервера больше такой проблемы не наблюдалось.