Предисловие Ссылка на заголовок

Вот и пришла пора увеличить место на своём домашнем сервере, для этого было куплено 2 диска разных производителей, но одинакового объёма.
Захотелось сделать soft RAID1, но мне не очень подходит mdadm, так как я хочу иметь более гибкое зеркало, которое можно будет легко расширить в будущем, а не выделять сразу большой объём.
Решил попытать счастья с LVM RAID, но информации по нему, в сжатом виде, мало, в основном всё заканчивает на том, как его создать. Попробую исправить этот пробел.

Мои диски

Мои диски

LVM Ссылка на заголовок

Нам понадобится 2 диска, если вы собираетесь настраивать RAID, если нет, то просто пропускайте части с настройкой второго диска.

Для тестирования необязательно иметь настоящие диски, можно использовать обычные файлы: How to create virtual block device (loop device/filesystem) in Linux

Заметка
Имена дисков заменены на sdX, sdY, sdZ, во избежание потери данных на реальных носителях.

Инициализация Ссылка на заголовок

Казалось бы, сделал pvcreate над диском и готово, но не тут то было…
Согласно рекомендациям1 2, стоит всегда создавать разделы на диске, во избежание проблем с софтом, который не знает об LVM и будет считать диск пустым.

Для разбивки диска я буду использовать gdisk, обычно уже установлен, но если что, устанавливается командой:

Bash
apt install gdisk
Предупреждение
Убедитесь, что вы используете верный диск в командах, так как это уничтожит все данные на диске!
Bash
gdisk /dev/sdX
Bash
# Смотрим разделы и проверяем, тот ли мы диск выбрали.
p

# Создаём пустую GUID partition table.
o # жмём `y`, чтобы удалить все разделы и создать GPT запись.

# Создаём первый и единственный раздел на весь диск.
n
1
<enter>
<enter>
8e00 # Указываем, что данный раздел относится к LVM.

# Теперь можно просмотреть то, что получилось.
p

# Если всё устраивает, то осталось записать изменения на диск.
w # жмём `y`, чтобы подтвердить запись.

проделываем то же самое со вторым диском.

Добавляем диски в LVM

Bash
pvcreate /dev/sdX1 /dev/sdY1
# или коротко
pvcreate /dev/sd[XY]1

Создаём группу vgdata из двух дисков

Bash
vgcreate vgdata /dev/sdX1 /dev/sdY1
# или коротко
vgcreate vgdata /dev/sd[XY]1

Простой логический диск Ссылка на заголовок

Создаём простой логический диск с именем lv0 на 3ГБ:

Bash
lvcreate --size 3G --name lv0 vgdata
# или коротко
lvcreate -L 3G -n lv0 vgdata

RAID 1 (mirror) Ссылка на заголовок

Создаём логический диск с RAID 1 под именем lvmirror на 3ГБ:

Bash
lvcreate --size 3G --name lvmirror --mirrors 1 vgdata
# или коротко
lvcreate -L 3G -n lvmirror -m1 vgdata

можно указать флаг --nosync, чтобы пропустить синхронизацию пустого зеркала.

Смотрим что получилось Ссылка на заголовок

Bash
lvs -a -o +devices

Колонка Cpy%Sync показывает, процент синхронизации, а Devices, устройства, на которых находятся данные логического диска.

FS Ссылка на заголовок

Осталось создать файловую систему:

Bash
mkfs.ext4 /dev/vgdata/lvmirror

И можно примонтировать и пользоваться

Bash
mount /dev/vgdata/lvmirror /mnt/

Тестируем LVM RAID 1 и учимся чинить Ссылка на заголовок

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

Для начала, посмотрим, как у нас всё выглядит до начала тестов:

Bash
lvs -a -o +devices,lv_health_status
LV                  VG     Attr       LSize Cpy%Sync Devices                                   Health
lvmirror            vgdata rwi-aor--- 3.00g 100.00   lvmirror_rimage_0(0),lvmirror_rimage_1(0)
[lvmirror_rimage_0] vgdata iwi-aor--- 3.00g          /dev/sdX1(1)
[lvmirror_rimage_1] vgdata iwi-aor--- 3.00g          /dev/sdY1(1)
[lvmirror_rmeta_0]  vgdata ewi-aor--- 4.00m          /dev/sdX1(0)
[lvmirror_rmeta_1]  vgdata ewi-aor--- 4.00m          /dev/sdY1(0)

Теперь мы можем приступать к тестированию, но сначала:

Предупреждение
Убедитесь, что вы используете верный диск в командах, так как это может привести к потере данные на диске!

Отвал диска (ресинхронизация) и его замена Ссылка на заголовок

В данном случае, мы будем симулировать отвал диска, через изменение его состояния 3

Отключаем диск sdX:

Bash
echo offline > /sys/block/sdX/device/state

Теперь, чтобы LVM понял, что с диском что-то не то, нужно записать на диск данные.

Если FS есть:

Bash
echo test > /mnt/test.txt 

Если FS нет(эта команда уничтожит FS, если она есть!):

Bash
dd if=/dev/zero of=/dev/vgdata/lvmirror count=10

Смотрим результат:

Bash
lvs -a -o +devices,lv_health_status
/dev/sdX: open failed: No such device or address
/dev/sdX: open failed: No such device or address
/dev/sdX: open failed: No such device or address
WARNING: Couldn't find device with uuid VkIceg-2ZVd-tTuZ-HgHz-EblT-5GwQ-oH3gKM.
WARNING: VG vgdata is missing PV VkIceg-2ZVd-tTuZ-HgHz-EblT-5GwQ-oH3gKM (last written to /dev/sdX1).
WARNING: Couldn't find all devices for LV vgdata/lvmirror_rmeta_0 while checking used and assumed devices.
WARNING: Couldn't find all devices for LV vgdata/lvmirror_rimage_0 while checking used and assumed devices.
LV                  VG     Attr       LSize Cpy%Sync Devices                                   Health
lvmirror            vgdata rwi-aor-p- 3.00g 100.00   lvmirror_rimage_0(0),lvmirror_rimage_1(0) partial
[lvmirror_rimage_0] vgdata iwi-aor-p- 3.00g          [unknown](1)                              partial
[lvmirror_rimage_1] vgdata iwi-aor--- 3.00g          /dev/sdY1(1)
[lvmirror_rmeta_0]  vgdata ewi-aor-p- 4.00m          [unknown](0)                              partial
[lvmirror_rmeta_1]  vgdata ewi-aor--- 4.00m          /dev/sdY1(0)

Обратите внимание, статус Health стал partial

Теперь запишем рандомные данные на диск, чтобы можно было увидеть рассинхронизацию:

FS есть, пишем в файл /mnt/random.file:

Bash
dd if=/dev/urandom of=/mnt/random.file bs=10M count=10 

FS нет(эта команда уничтожит FS, если она есть!):

Bash
dd if=/dev/urandom of=/dev/vgdata/lvmirror bs=10M count=10

Включаем диск sdX обратно:

Bash
echo running > /sys/block/sdX/device/state

Смотрим результат:

Bash
lvs -a -o +devices,lv_health_status
LV                  VG     Attr       LSize Cpy%Sync Devices                                   Health
lvmirror            vgdata rwi-aor-r- 3.00g 100.00   lvmirror_rimage_0(0),lvmirror_rimage_1(0) refresh needed
[lvmirror_rimage_0] vgdata Iwi-aor-r- 3.00g          /dev/sdX1(1)                              refresh needed
[lvmirror_rimage_1] vgdata iwi-aor--- 3.00g          /dev/sdY1(1)
[lvmirror_rmeta_0]  vgdata ewi-aor-r- 4.00m          /dev/sdX1(0)                              refresh needed
[lvmirror_rmeta_1]  vgdata ewi-aor--- 4.00m          /dev/sdY1(0)

Ошибки и предупреждения об отсутствии диска пропали, но статус Health изменился на refresh needed

Чиним Ссылка на заголовок

Запускаем синхронизацию командой:

Bash
lvchange --refresh /dev/vgdata/lvmirror

Но если диск выпал, я бы рекомендовал его заменить на новый, проинициализировав его как в начале статьи и добавив в PV и VG:

Bash
pvcreate /dev/sdZ1
vgextend vgdata /dev/sdZ1

И заменив диск у зеркала:

Bash
lvconvert --replace /dev/sdX1 /dev/vgdata/lvmirror /dev/sdZ1

Замена мёртвого диска Ссылка на заголовок

Теперь давайте просимулируем замену мёртвого диска, для этого нам придётся стереть заголовок нашего диска, чтобы он выглядел как новый:
Эта команда уничтожит данные на диске!

Bash
dd if=/dev/zero of=/dev/sdX bs=10M count=1

При вызове

Bash
lvs -a -o +devices,lv_health_status

Мы увидим тот же результат, что и при отвале диска, статус Health стал partial, но чинится это по другому.

Чиним Ссылка на заголовок

Удалим старый диск из VG

Bash
vgreduce --removemissing --force vgdata

Так как мы стёрли заголовки диска, нам придётся проинициализировать диск заново и добавить его в PV и VG:

Bash
pvcreate /dev/sdX1
vgextend vgdata /dev/sdX1

И нужно починить наше зеркало

Bash
lvconvert --repair /dev/vgdata/lvmirror

Автоматически запуститься ресинхронизация.

Конвертируем логический диск из RAID 1 в обычный Ссылка на заголовок

Bash
lvconvert -m0 /dev/vgdata/lvmirror

Конвертируем логический диск из обычного в RAID 1 Ссылка на заголовок

Bash
lvconvert -m1 /dev/vgdata/lvmirror

Увеличиваем размер диска с зеркалом Ссылка на заголовок

Bash
umount /dev/vgdata/lvmirror
# Добавляем 5GB к диску
lvresize --resizefs --size +5G /dev/vgdata/lvmirror
# Смотрим результат
lvs

Уменьшаем размер диска с зеркалом Ссылка на заголовок

Bash
umount /dev/vgdata/lvmirror
# Делаем диск равным 4GB
lvresize --resizefs --size 4G /dev/vgdata/lvmirror
# Смотрим результат
lvs

Мониторинг Ссылка на заголовок

Для мониторинга состояния LVM я написал exporter для prometheus
lvm_exporter

Как я всё сломал Ссылка на заголовок

Пока писал статью, успел сломать тестовый LVM

Inconsistent metadata Ссылка на заголовок

Когда отключил диск, я решил удалить лишнее зеркало (у меня было 2 LV зеркальных), после подключения диска обратно, у меня появилась ошибка при любой команде LVM:

WARNING: ignoring metadata seqno 20 on /dev/sdX1 for seqno 21 on /dev/sdY1 for VG vgdata.
WARNING: Inconsistent metadata found for VG vgdata
WARNING: outdated PV /dev/sdX1 seqno 20 has been removed in current VG vgdata seqno 21.

После долгих поисков, нашёл нужную мне команду в багтрекере 4, которая мне помогла:

Bash
vgck --updatemetadata vgdata