[Из песочницы] Как я сделал зеркалирование виртуальных машин для Free ESXi
В своей домашней лаборатории я использую бесплатную виртуализацию от VMware — это дешево и надежно. Сначала был один сервер, потом в него начал добавлять локальные датасторы, потом собрал второй сервер… Стандартной проблемой при этом был переезд виртуальной машины. Делая эти операции вручную, я наткнулся на один способ, который позволял переключить работающую виртуальную машину на копии флэтов совершенно в другом месте. Способ крайне прост: достаточно создать снапшот виртуальной машины, склонировать флэты в новое место, а затем в дельте перебить ссылку на родительский диск. Гипервизор не держит файлы метаданных диска открытыми, поэтому при удалении снапшота происходит сливание с новым диском, а старый можно спокойно удалять. Этот способ прекрасно работает без всякого VDDK, который недоступен на бесплатных гипервизорах и которым пользуется, например, Veeam в похожей ситуации.
Я без труда автоматизировал эту процедуру на python, применив еще несколько трюков, которые, при наличии запросов, смогу раскрыть в следующих статьях. Немного позже нашелся хороший человек из моих бывших коллег по цеху, который согласился написать гуй, последний, правда, реализован на Unity, но для получившегося бесплатного солюшена, названного нами Extrasphere, это было совсем не плохо. Чем не игрушка для админа?
Сделав для своей домашней лаборатории миграцию виртуальных машин, я задумался о защите от сбоев. Минимальным требованием было резервирование работающей виртуалки, максимально недостижимым же отсутствие отставания резервной копии от оригинала. Не то чтобы у меня были такие данные, где потеря 15 секунд критична, по правде сказать, для меня не критично потерять и пару дней, но вот к такому идеалу хотелось прийти с заделом на будущее.
Я не стану приводить анализ и сравнение доступных решений — это было давно, заметок с тех пор не сохранилось, помню только о немыслимой тяге к велосипедизму.
На бесплатном гипервизоре можно сделать простейший бэкап-агент из Linux машины, к которой цеплять флэты заснапшоченной виртуальной машины. Такое решение хорошо подходит для создания фуловых резервных копий, но абсолютно не годится для инкрементального бэкапа, т.к. родной CBT не доступен для бесплатных гипервизоров.
Я подумал, что неплохо бы самому запилить CBT, но как? Слышал про Zerto и SRM с их vSCSIFilter, но скачав open-source пакет для ESXi не нашел там ничего похожего — ну разве что символьное устройство написать можно. Решил взглянуть на устройство hbr_filter, там, к моему удивлению, все оказалось не слишком сложно. Три недели экспериментов — и вот я уже могу навесить свой фильтр-драйвер на диск виртуалки и трэкать изменения.
А что если не просто трэкать изменения, а реплицировать их? Тут самая большая опасность в том, чтобы начать писать тонну кода обеспечивающего канал передачи: тут вытащи изменения, упакуй и отправь в сеть, там прими, распакуй и запиши, а еще и целостность на каждом шагу нужно обеспечить и обработку ошибок. Без пары агентов кажется не обойтись. Достаточно взглянуть на архитектуру Zerto, чтобы понять, что написать и стабилизировать такое решение в одиночку нереально:
Рис. 1. Архитектура Zerto Virtual Replication из рекламного ролика.
Тут я вспомнил, что ESXi и сам умеет писать по сети через iSCSI и NFS к примеру. Все что нужно — это примонтировать таргетный датастор локально. А если еще и включить реплику, то можно писать в неё прямо из фильтр-драйвера! Я начал эксперименты: поначалу не знал, что делать с включенной репликой и просто грузил её с Ubuntu Live CD, через пару-тройку недель начала получаться работоспособная копия, а затем и научился передавать изменения на лету. Причем исходная машина не получает подтверждения записи, пока не пройдут записи в оба получателя. Так у меня получилась репликация с нулевым отставанием.
Технология получилась безагентной, кода минимум, создание реплики тут же быстро накидал на python. За такую непохожесть на классическую репликацию и простоту я решил называть её зеркалированием.
Проблему же включенного зеркала я решил написанием простенького бутлоадера, а чтобы от него хоть какая-то польза была, на буте он показывает последний статус зеркала, а затем замирает. В итоге фактическое потребление памяти стремиться к нулю, CPU немного тратится при передаче данных, но установленный агент съел бы никак не меньше. Как результат график дисковой активности на запись у зеркала и исходной машины идентичны.
Рис. 2. Потребление CPU на исходной машине с нагрузкой.
Рис. 3. Потребление CPU на зеркале в тот же период.
Рис. 4. Потребление памяти на исходной машине с нагрузкой.
Рис. 5. Потребление памяти на зеркале в тот же период.
Рис. 6. Дисковая производительность исходной машины под нагрузкой.
Рис. 7. Дисковая производительность зеркала за тот же период.
Для того, чтобы проверить состояние зеркала я сделал тестовые машины, которые запускаются как linked-clone от снапшота зеркала. При желании снапшот можно хранить и потом запускать тесты повторно, а если тест очень понравился, то его можно превратить в персистентную виртуальную машину встроенной миграцией, про которую я рассказывал вначале повести.
Локальный таргет — это хорошо, а что делать, если необходимо зеркалировать в другой офис/город? Даже если канал связи будет достаточно широким, то продолжительность ответа серьезно просадит производительность исходной машины, мы же помним, что исходная машина не получает подтверждение записи, пока она не завершится в оба получателя. Решение здесь крайне простое: нужно расширить интервал неопределенности записи с нуля до некоторого разумного значения. Скажем, допустимое отставание в 3–5 секунд обеспечат как хорошую сохранность данных, так и приличную производительность. Над этим решением я как раз работаю в данный момент. На очереди работа без ssh и консистентность уровня приложений, где тоже не обойдется без трюков, которыми я с радостью поделюсь.