abstract: Этот пост описывает организацию системного диска на машинах в облаке и объясняет, почему именно так.
Предисловие: Всё написанное тут касается системных дисков создаваемых при установке виртуальных машин. Пользователи имеют полное право делать что хотят с этими дисками, и уж, тем паче, решать самостоятельно, как организовывать место на дополнительных дисках.
Мотивация
Мы должны предоставлять диски системы в таком виде, который даст пользователям достаточную свободу делать «что хочешь», и в то же время обеспечивать достаточную простоту и удобство для пользователей, которым нужно «просто работать». Хотя проблема чуть более сложная, поскольку речь идёт не об удобном пульте телевизора, а об инструменте в работе, так что правильнее говорить про удобство типовых сценариев и возможность реализовывать свои собственные.
Вот проблемы, которые возникают в связи с этим:
- Возможность изменить размер диска и корневой файловой системы
- Возможность создать дополнительные разделы
- Возможность подключить диски от одной машине к другой
- С этого диска надо ещё и загрузиться
Наиболее примитивным решением является файловая система на весь диск (/dev/xvda подмонтирован как '/'). Её очень легко менять в размере, после изменения размера блочного устройства достаточно просто запустить команду «ресайз» для файловой системы. Её так же легко подключить к другим виртуальным машинам. Однако, отсутствие таблицы разделов приводит к тому, что дополнительные разделы создать нельзя — обычный колхоз: рут, home и /var/www (у кого-то это /srv/www, у кого-то /home/websitename и т.д.) оказываются на одном разделе с /var/log и прочими служебными файлами. Легко, просто, но на роль продвинутого инструмента совсем не тянет. А главное, новые разделы можно сделать только подключив дополнительные диски. Более того, даже swap-раздел не сделать, приходится изголяться с fallocate или dd для создания файла подкачки.
Второй вариант — старая-добрая таблица разделов. /dev/xvda1, /dev/xvda5, /dev/xvda6 и т.д. Плюсы: просто, понятно, легко подключать к другим машинам, но очень трудно менять размер, например, root'а. Нужно удалить раздел подкачки, изменить размер раздела в таблице разделов, изменить размер файловой системы, что-то сделать с файлом подчкачки. Если же на диске есть разделы с данными, нужно запускать жуткие и опасные процедуры перемещения таблицы разделов (а с учётом платных дисковых операций это вообще не вариант).
И, наконец, третий вариант — LVM. Что хорошо: ресайз файловой системы возможен и очень прост. Легко добавлять/удалять разделы. При этом мы имеем некоторые решаемые проблемы с подключением дисков в другие машины (как и какие там проблемы — см. ниже). Однако, есть маленькая проблемка. С lvm мы грузиться не умеем. Совсем.
Так что пришлось сделать менее удобный, но рабочий четвёртый вариант.
Наше решение
На системном диске создаётся таблица разделов с двумя primary (первичными) разделами: /dev/xvda1 — /boot и /dev/xvda2 — физический том для LVM. Загрузка ядра идёт с /dev/xvda1, который маленький и (по-хорошему) не должен меняться в размере, файловая система и файл подкачки — на LVM внтури второго раздела.
Плюсы? Можно решить все задачи: изменение размеров раздела, подключение к другим машинам, загрузка, создание неограниченного числа разделов.
Минус: ресайз уже не «легко и просто» — чуть-чуть придётся напрячься. Но, всё-таки возможен с разумными усилиями.
Так как нерешённых проблем в этом варианте не осталось, мы остановились на нём. Я бы, конечно, предпочёл иметь «чистый LVM», но его парсинг из pygrub слишком сложен, особенно с учётом наличия вышестоящего LVM (мы используем LVM over iSCSI для хранения дисков клиентов).
Типовые операции
Начнём с самой частой — изменение размеров системного раздела.
- Увеличить размер блочного устройства (панель управления)
- Выполнить команду ptmax /dev/xvda2
- Перезагрузиться (спасибо линуксу, отказывающемуся делать перечитывание заблокированного диска с корневым разделом)
- Выполнить команду pvresize /dev/xvda2
- Посмотреть на свободные PE в VG: vgdisplay
- Увеличить размер логического тома: lvresize /dev/../sys -l +(число свободных extents)
- Изменить размер файловой системы: resize2fs /dev/../sys
Сложно? Да. Гибко и функционально? Да! Почему? Потому что использование LVM открывает множество «обходных» путей. Например, можно увеличивать размер раздела, который не является последним в списке. Или, например, легко можно создать любое число нужных логических томов.
Немного о ptmax. Так получилось, что эту утилиту нам (мне) пришлось написать с нуля. Самого кода там — с гулькин нос, большую часть составляют проверки «правильно ли всё делаем». Суть утилиты — если в таблице разделов у раздела есть свободное место за ним, увеличивает раздел до максимально возможного размера. Типовой сценарий для увеличения размера диска виртуальной машины.
Раньше это приходилось делать методом «удаления/пересоздания» раздела в fdisk, что мягко говоря, было не очень безопасно. Утилита под GPL, традиционно на гитхабе: github.com/amarao/ptmax.
Немного о многоточии. Вместо многоточия следует использовать tab использовать имя VG, которое используется в машине. Имя VG совпадает с hostname на момент установки. Почему мы используем его? Потому что если бы мы использовали одно и то же имя, то при подключении диска в другую машину возникала бы коллизия (причём коллизию можно было бы решить, переименовав VG, но только в одну сторону — задать такое же имя для второго VG в системе нельзя). Так что у каждого VG каждой машины «своё» имя. Упреждая вопросы: использовать одинаковое имя сервера для двух разных виртуальных машин — муветон. Случай подключения снапшота мы разберём чуть ниже.
Второй типовой сценарий — создание ещё одного раздела. По большому счёту, мало отличается от первой процедуры:
- Увеличить размер блочного устройства (панель управления)
- Выполнить команду ptmax /dev/xvda2
- Перезагрузиться (спасибо линуксу, отказывающемуся делать перечитывание заблокированного диска с корневым разделом)
- Выполнить команду pvresize /dev/xvda2
- Посмотреть на свободные PE в VG: vgdisplay
- Создать раздел: lvcreate /dev/VGNAME -n LVNAME -L XXXMb
- Создать файловую систему на нём: mkfs.ext4 /dev/VGNAME/LVNAME
- подмонтировать систему и прописать её в fstab
Следующий сценарий чуть более сложный — подключение диска на «чужой» виртуальной машине.
После подключения диска нужно активировать VG:
- pvscan /dev/xvdb (или другое имя устройства)
- vgscan
- lvscan
- lvdisplay
- lvchange -a y /dev/VGNAME/LVNAME (виден в выводе предыдущего пункта)
- mount/umount
После окончания работ, если диск нужно отключать, нужно сделать «деактивацию»:
- lvchange -a n /dev/VGNAME/LVNAME
- vgchange -a n /dev/VGNAME
- pvchange -a n /dev/xvdb
После этого диск можно будет отключать «на ходу».
Автор: amarao