Итак, мы рассмотрели, каким образом можно создать виртуальное блочное устройство DRBD и синхронизировать его участников. Перейдем к автоматизации процесса инициализации блочных устройств и контроля за их работой.
Современные реализации DRBD не требуют для обеспечения контроля за собой сторонних приложений, все, что нужно, можно получить от утилит самого DRBD. Невозможность получить от DRBD информации о состоянии блочных устройств само по себя является достаточным поводом для паники.
Наша задача на данном этапе состоит в том, чтобы при запуске физического сервера провести проверку на доступность всех членов виртуальных блочных устройств, установить режимы работы блочных устройств и, если на будет необходимость, информировать администратора о нештатном развитии ситуации.
Будем считать, что все блочные устройства уже созданы и синхронизированы. Создадим условия для автоматизации процесса.
Создаем файл списка DRBD устройств:
# mkdir -p /etc/custom/hdd/drbd
# touch /etc/custom/hdd/drbd/list
# touch /etc/custom/hdd/drbd/list
Наименования устройств вносим с разделителем в виде пробельного символа. К имени устройства, через разделитель в виде "слэша", прикрепляем назначенный ему статус (primary или secondary):
# cat /etc/custom/hdd/drbd/list
drbd0/primary drbd1/primary drbd2/secondary ... drbdX/status
Пакет DRBD позволяет получать список используемых устройств в интерактивном режиме, но нам нужен список устройств, которые мы уже настроили, протестировали, одобрили и включили в рабочую схему. Нужно это для того, чтобы скрипты не обращали внимания на те устройства, что находятся на предварительной настройке, тестировании или профилактике.
Напишем скрипт проверяющий состояние членов устройств DRBD с определённой периодичностью, в течении работы, устанавливающий режим работы устройства и информирующего администратора об обнаруженных проблемах:
# touch /etc/custom/hdd/drbd/check-drbd.sh
# chmod ugo+x /etc/custom/hdd/drbd/check-drbd.sh
# chmod ugo+x /etc/custom/hdd/drbd/check-drbd.sh
#!/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
HOSTNAME=`cat /etc/hostname`
OBJECTS=`cat /etc/custom/hdd/drbd/list`
DATE=`date +"%Y-%m-%d %H:%M:%S"`
EMAIL=`cat /etc/custom/hdd/email`
# Определяем функцию уведомления администратора о нештатном развитии ситуации
function send-report() {
local LOCAL_OBJECT=$1
local LOCAL_REPORT=$2
# Посылаем электронное письмо с уведомлением о проблеме
echo -e "Content-Type: text/plain; charset="utf-8"\nSubject: Warning DRBD: ${HOSTNAME}: /dev/${LOCAL_OBJECT}\n${DATE}.\nHost: ${HOSTNAME}.\nDevice: /dev/${LOCAL_OBJECT}.\n${LOCAL_REPORT}" | sendmail -F${HOSTNAME} ${EMAIL}
}
# Проверяем, не установлены ли флаги блокировки от текущего уровня схемы
if [ -e /tmp/custom/drbd/lock ]
then
exit 0
fi
# Устанавливаем флаги блокировки на время работы скрипта
mkdir -p /tmp/custom/drbd
touch /tmp/custom/drbd/lock
# Проверяем факт запуска DRBD по созданным им конструкциям
if [ ! -e /proc/drbd ]
then
send-report "DRBD" "Warning! DRBD не запущен."
echo >&2 "Warning! DRBD не запущен."
exit 1
fi
# Перебираем в цикле все наши DRBD устройства
for OBJECTIVE in ${OBJECTS}
do
# Получаем в переменные имя устройства и предназначенную ему роль
OBJECT=`echo ${OBJECTIVE} | awk -F / '{print $1}'`
ROLE=`echo ${OBJECTIVE} | awk -F / '{print $2}'`
# Проверяем, работает ли устройство в полноценной связке с удалённым по сети дубликатом
if [ `drbdadm cstate ${OBJECT} 2>/dev/null | grep "Connected"` ]
then
# Проверяем, доступно ли DRBD устройство для полноценного использования локально
if [ "`drbdadm dstate ${OBJECT} 2>/dev/null | awk -F / '{print $1}'`" = "UpToDate" ]
then
# Проверим, доступен ли для полноценной работы удалённый по сети DRBD дубликат
if [ "`drbdadm dstate ${OBJECT} 2>/dev/null | awk -F / '{print $2}'`" != "UpToDate" ]
then
# Если удалённый по сети DRBD дубликат не готов к работе, то для локального устройства принудительно выставляем роль primary (если в это есть необходимость), что бы некоторое время продержаться на одном диске, до замены вышедшего из строя
if [ "${ROLE}" != "primary" ]
then
ROLE="primary"
fi
fi
# Проверяем на предмет уже назначенной роли
if [ "`drbdadm state ${OBJECT} | awk -F / '{print $1}' | tr A-Z a-z`" != "${ROLE}" ]
then
# Если локальный член DRBD устройства корректно работает, то назначаем ему заданную заранее роль (это может быть как primary так и secondary)
echo "Waiting 10 seconds for correct setup role DRBD resource /dev/${OBJECT}..."
drbdsetup /dev/${OBJECT} ${ROLE}
sleep 10
if [ "`drbdadm state ${OBJECT} | awk -F / '{print $1}' | tr A-Z a-z`" != "${ROLE}" ]
then
send-report ${OBJECT} "Panic! За 10 секунд не произошло применение ролей членов DRBD устройства."
echo >&2 "Panic! За 10 секунд не произошло применение ролей членов DRBD устройства /dev/${OBJECT}."
fi
fi
else
send-report ${OBJECT} "Panic! DRBD устройство работает не корректно или не применимо в текущей конфигурации."
echo >&2 "Panic! DRBD устройство /dev/${OBJECT} работает не корректно или не применимо в текущей конфигурации."
fi
else
send-report ${OBJECT} "Warning! DRBD устройство работает некорректно в ожидании подключения к удалённому узлу."
echo >&2 "Warning! DRBD устройство /dev/${OBJECT} работает некорректно в ожидании подключения к удалённому узлу."
fi
done
# Удаляем флаг блокировки во время исполнения
rm --force /tmp/custom/drbd/lock
exit 0
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
HOSTNAME=`cat /etc/hostname`
OBJECTS=`cat /etc/custom/hdd/drbd/list`
DATE=`date +"%Y-%m-%d %H:%M:%S"`
EMAIL=`cat /etc/custom/hdd/email`
# Определяем функцию уведомления администратора о нештатном развитии ситуации
function send-report() {
local LOCAL_OBJECT=$1
local LOCAL_REPORT=$2
# Посылаем электронное письмо с уведомлением о проблеме
echo -e "Content-Type: text/plain; charset="utf-8"\nSubject: Warning DRBD: ${HOSTNAME}: /dev/${LOCAL_OBJECT}\n${DATE}.\nHost: ${HOSTNAME}.\nDevice: /dev/${LOCAL_OBJECT}.\n${LOCAL_REPORT}" | sendmail -F${HOSTNAME} ${EMAIL}
}
# Проверяем, не установлены ли флаги блокировки от текущего уровня схемы
if [ -e /tmp/custom/drbd/lock ]
then
exit 0
fi
# Устанавливаем флаги блокировки на время работы скрипта
mkdir -p /tmp/custom/drbd
touch /tmp/custom/drbd/lock
# Проверяем факт запуска DRBD по созданным им конструкциям
if [ ! -e /proc/drbd ]
then
send-report "DRBD" "Warning! DRBD не запущен."
echo >&2 "Warning! DRBD не запущен."
exit 1
fi
# Перебираем в цикле все наши DRBD устройства
for OBJECTIVE in ${OBJECTS}
do
# Получаем в переменные имя устройства и предназначенную ему роль
OBJECT=`echo ${OBJECTIVE} | awk -F / '{print $1}'`
ROLE=`echo ${OBJECTIVE} | awk -F / '{print $2}'`
# Проверяем, работает ли устройство в полноценной связке с удалённым по сети дубликатом
if [ `drbdadm cstate ${OBJECT} 2>/dev/null | grep "Connected"` ]
then
# Проверяем, доступно ли DRBD устройство для полноценного использования локально
if [ "`drbdadm dstate ${OBJECT} 2>/dev/null | awk -F / '{print $1}'`" = "UpToDate" ]
then
# Проверим, доступен ли для полноценной работы удалённый по сети DRBD дубликат
if [ "`drbdadm dstate ${OBJECT} 2>/dev/null | awk -F / '{print $2}'`" != "UpToDate" ]
then
# Если удалённый по сети DRBD дубликат не готов к работе, то для локального устройства принудительно выставляем роль primary (если в это есть необходимость), что бы некоторое время продержаться на одном диске, до замены вышедшего из строя
if [ "${ROLE}" != "primary" ]
then
ROLE="primary"
fi
fi
# Проверяем на предмет уже назначенной роли
if [ "`drbdadm state ${OBJECT} | awk -F / '{print $1}' | tr A-Z a-z`" != "${ROLE}" ]
then
# Если локальный член DRBD устройства корректно работает, то назначаем ему заданную заранее роль (это может быть как primary так и secondary)
echo "Waiting 10 seconds for correct setup role DRBD resource /dev/${OBJECT}..."
drbdsetup /dev/${OBJECT} ${ROLE}
sleep 10
if [ "`drbdadm state ${OBJECT} | awk -F / '{print $1}' | tr A-Z a-z`" != "${ROLE}" ]
then
send-report ${OBJECT} "Panic! За 10 секунд не произошло применение ролей членов DRBD устройства."
echo >&2 "Panic! За 10 секунд не произошло применение ролей членов DRBD устройства /dev/${OBJECT}."
fi
fi
else
send-report ${OBJECT} "Panic! DRBD устройство работает не корректно или не применимо в текущей конфигурации."
echo >&2 "Panic! DRBD устройство /dev/${OBJECT} работает не корректно или не применимо в текущей конфигурации."
fi
else
send-report ${OBJECT} "Warning! DRBD устройство работает некорректно в ожидании подключения к удалённому узлу."
echo >&2 "Warning! DRBD устройство /dev/${OBJECT} работает некорректно в ожидании подключения к удалённому узлу."
fi
done
# Удаляем флаг блокировки во время исполнения
rm --force /tmp/custom/drbd/lock
exit 0
Цель скрипта в том, чтобы сделать доступным виртуальное блочное устройство в том случае, если доступен в полной мере один или более из его членов. Для кластерных систем достаточно было бы сделать всех членов блочного устройства доступными для чтения и записи (условно говоря, сделать всем роли Primary), но в нашем случае необходимо следить за отсутствием конфликтов чтения/записи и целостностью данных членов виртуального устройства. Суть в том, что если скрипт обнаружит недоступность того из членов DRBD устройства, что должен иметь роль первичного, об этом должен сразу же узнать администратор, провести соответствующие работы с последующим восстановлением файловой системы.
Одна из операций созданного нами скрипта производит проверку на подключение виртуального устройства с помощью команды "drbdadm cstate". У упомянутой команды довольно многовариантный вывод, но только одно из них говорит о том, что все члены виртуального устройства подключены и доступны, это: "Connected" - оно говорит о том, что все устройства на связи и готовы к любым операциям с ними. Все остальные варианты вывода команды "drbdadm cstate" говорят о том или ином уровне недоступности устройства и все эти состояния возникают в момент неисправности связки членов виртуального устройства, что служит достаточным поводом объявить тревогу. Устройства могут быть недоступны в момент ввода их в рабочую схему, и для обхода этих критических ситуаций мы создали ручной список проверяемых DRBD устройств; просто не будем включать в него устройства, что ещё не синхронизированы и не введены в рабочую схему.
Созданный нами скрипт автоматического применения ролей членов устройств DRBD должен запускаться периодически. Думаю, что период в десять минут вполне приемлем; если роли к устройствам уже применены ранее, то скрипт просто это проверит (доли секунды), а в случае сбоя работы устройств - чем раньше мы это обнаружим, тем лучше.
Размещаем команду запуска скрипта в таблице /etc/crontab:
# cat /etc/crontab
....
*/10 * * * * root /etc/custom/hdd/drbd/check-drbd.sh &
....
*/10 * * * * root /etc/custom/hdd/drbd/check-drbd.sh &
....
Что бы не дожидаться периодического запуска вышеописанного скрипта при старте системы, разместим команду запуска в исправленном ранее скрипте управления DRBD (следует иметь в виду то, что DRBD может затратить одну-три минуты на освоение всего дискового массива, общий объём которого может достигать 10TB - потому дадим ему на это время отдельно, при первом запуске):
# vi /etc/init.d/drbd
....
case "$1" in
start)
....
# Проверяем успешность загрузки модуля DRBD по наличию созданных им служебных конструкций
if [ -e /proc/drbd ]
then
echo >&2 "DRBD driver started."
echo "Wait 300 seconds before start configuration..."
sleep 300
/etc/custom/hdd/drbd/check-drbd.sh
....
reload)
....
drbdadm adjust all
/etc/custom/hdd/drbd/check-drbd.sh &
;;
....
case "$1" in
start)
....
# Проверяем успешность загрузки модуля DRBD по наличию созданных им служебных конструкций
if [ -e /proc/drbd ]
then
echo >&2 "DRBD driver started."
echo "Wait 300 seconds before start configuration..."
sleep 300
/etc/custom/hdd/drbd/check-drbd.sh
....
reload)
....
drbdadm adjust all
/etc/custom/hdd/drbd/check-drbd.sh &
;;
....
Переход к применению файловой системы XFS.