Маленькие «малинки» в крупном дата-центре
В мае у нас появились новые серверы на базе Raspberry Pi 4. И ребята из Selectel Community (это такой неформальный телеграм-чат компании) часто спрашивали, как нам вообще удалось интегрировать их в систему автоматической сдачи. Спустя время мы окинули сделанное ретроспективным взором и готовы подробно ответить на этот вопрос.
Тема использования «малинок» в промышленных масштабах не нова — в сети можно найти множество публикаций на тему сборки вычислительных кластеров. Вначале они представляли собой самодельные фермы, где самым интересным была возможность добавить побольше плат или приспособить водяную систему охлаждения. Но с ростом интереса начали появляться уже готовые кронштейны для монтирования «малинок» в стандартную 19» стойку. Даже были попытки создать blade-варианты.
Но, несмотря на весь оптимизм в медиасфере, вопрос, удастся ли вообще интегрировать «малинки» в дата-центры Selectel, оставался открытым.
Общие требования к размещению в дата-центре
Чтобы понять, что же могло помешать, рассмотрим основные отличия «малинок» от «стандартных» серверов. Под «стандартными» подразумеваются серверы линейки Chipcore на базе десктопного железа.
Чтобы разместить сервер в дата-центре, он должен удовлетворять следующим требованиям:
- Поддержка сетевых интерфейсов. Самое очевидное требование. Сервер должен быть доступен клиенту по «белому» IP-адресу. Обеспечивается Gigabit Ethernet портом.
- Размещение в стойке. На время тестов мы использовали распечатанные на 3D-принтере салазки. На 1 монтажный юнит приходится 12 «малинок».
- Удаленное управление питанием. По умолчанию питание происходит через предназначенный для этого порт USB Type-C, что дает только ручное управление.
Но через 40-пиновый разъем можно подключить модуль PoE HAT. В таком случае управлять питанием удаленно можно через коммутатор, включая или отключая питание на порту. - Независимость от локальных дисковых устройств. Аренда выделенных серверов предполагает полный доступ клиента к железу. Более того, диски могут быть заменены по требованию. В этом случае они должны быть полностью очищены и не содержать дополнительных данных, а развертывание сервера не должно на них опираться.
- Загрузка по сети (PXE). Самый непонятный и вызывающий вопросы пункт. Мы знали, что «малинки» поддерживают загрузку по PXE, но, как в действительности это работает, оставалось неизвестным.
На последнем пункте остановимся подробнее. Нужно учитывать, что Raspberry Pi относится к железу для встраиваемых систем. А на них процесс инициализации и загрузки системы заметно отличается от привычного.
Процесс загрузки «обычного» сервера
Для сравнения, вкратце рассмотрим, как происходит загрузка на «обычном» сервере.
- BIOS/UEFI. Система стартует с BIOS/UEFI, который инициализирует железо и передает управление первому устройству в списке загрузки. По умолчанию это первый диск в системе, но для загрузки по PXE первым выбирается нужный сетевой интерфейс. Важно, что BIOS/UEFI дает нам интерфейс для изменения этого списка и может его сохранять.
- NIC. После того, как сетевой интерфейс получил управление, он посылает в сеть широковещательный запрос DHCP, получает в ответе настройки TFTP (tftp-server-name и boot-file-name) и по ним загружает файл, которому передается управление.
- iPXE. В нашем случае мы возвращаем кастомизированный iPXE-загрузчик, который через параметр chain запрашивает iPXE-скрипт и получает сценарий загрузки сервера.
- Автоустановка / автозагрузка. В зависимости от выбора дистрибутива на базе шаблона генерируется уникальный сценарий (прежде всего данные подключения) автоустановки для конкретного сервера. После завершения автоустановки сценарий загрузки меняется, и iPXE в следующий раз получит другой шаблон загрузки. Загрузка через сетевой интерфейс позволяет нам гибко управлять загрузкой сервера, меняя только ответ сервера, с которого iPXE ожидает ответ.
Процесс загрузки «малинки»
Подробно процесс загрузки для Raspberry Pi 4 описан в официальной документации. Здесь же ограничимся деталями, важными в контексте сравнения.
- EEPROM. Старт «малинки» начинается с запуска прошивки из энергонезависимой микросхемы EEPROM. В сценарии она по умолчанию ищет файлы на /boot разделе SD-карты, необходимые для инициализации компонентов. В этом смысле ее можно сравнить с BIOS без графического интерфейса. Для изменения настроек и сценария загрузки (BOOT_ORDER) нужно полностью обновить файл загрузчика с применением опций из текстового файла и заново записать его в микросхему.
- Директория загрузки (/boot). По умолчанию загрузчик из EEPROM обращается к первому разделу SD-карты, где располагаются необходимые файлы для дальнейшей загрузки. Прежде всего это файл прошивки (firmware) для GPU, DTB-файлы (описание дерева устройств) и образ ядра kernel.img, из которого загружается операционная система. В установленной и загруженной системе этот раздел монтируется в /boot. Изменение опции BOOT_ORDER по сути меняет только устройство, с которого загрузчик ожидает получить файлы, но не их список.
Да, процесс сильно отличается. И это вызывает много вопросов о его интеграции в существующую схему. Но будем разбираться последовательно.
Обновление EEPROM
Для обновления EEPROM нам нужна предустановленная система с утилитой vcgencmd. Получить ее мы можем, загрузив образ Raspberry Pi OS и раскатав его напрямую на SD-карту.
wget https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-05-28/2021-05-07-raspios-buster-armhf-lite.zip
unzip -p 2021-05-07-raspios-buster-armhf-lite.zip | sudo dd of=/dev/sdX
Возвращаем SD-карту обратно в «малинку» и загружаемся с нее в операционную систему. Для входа по умолчанию используются логин и пароль pi / raspberry.
Здесь можно посмотреть текущие опции прошивки EEPROM:
pi@raspberrypi:~ $ vcgencmd bootloader_config
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
FREEZE_VERSION=0
Генерируем из файла прошивки файл конфигурации:
cp /lib/firmware/raspberrypi/bootloader/pieeprom-2019-11-18.bin new-pieeprom.bin
rpi-eeprom-config new-pieeprom.bin > bootconf.txt
В файле bootconf.txt необходимо изменить значение BOOT_ORDER для изменения порядка загрузки. Поскольку нас интересует загрузка по сети, сначала указываем загрузку по сети (2), затем — с SD-карты (1), и делать это нужно в цикле (f). Также можно указать максимальное количество попыток загрузки по сети:
BOOT_ORDER=0xf12
NET_BOOT_MAX_RETRIES=1
После подготовки bootconf.txt нужно применить настройки из него к файлу прошивки:
rpi-eeprom-config --out netboot-pieeprom.bin --config bootconf.txt new-pieeprom.bin
В конце записываем новый файл прошивки с нужными нам опциями в EEPROM:
sudo rpi-eeprom-update -d -f ./netboot-pieeprom.bin
Мы в Selectel любим одноплатники, так что собрали для вас еще подборку интересных статей на эту тему:
Загрузка «малинки» в PXE
После перезагрузки мы видим на экране монитора, что сервер начинает грузиться по сети. Одноплатник успешно получает адрес у DHCP-сервера и начинает запрашивать файлы с TFTP-сервера. Ошибка загрузки! Ведь мы еще не подготовили замену /boot директории на TFTP-сервере.
Для этого достаточно скопировать содержимое из директории /boot в установленной Raspberry Pi OS на удаленный TFTP-сервер. Например:
scp -r /boot/* root@tftp-server:/srv/tftp/
В нашем случае эти файлы лучше получить из папки /bootофициального репозитория (альтернативная ссылка).
После такой подготовки «малинка» успешно начнет загрузку по сети, получит по TFTP-протоколу запрошенные файлы и загрузится в уже установленную систему.
Остановитесь для оценки происходящего: используя логи TFTP-сервера, внимательно просмотрите список файлов, которые «малинка» запрашивает по сети. Для лучшего понимания будем сверяться с документацией, поясняя только для минимально необходимого набора файлов.
RRQ from 10.51.228.22 filename 04f2ea0a/start4.elf
RRQ from 10.51.228.22 filename config.txt
RRQ from 10.51.228.22 filename start4.elf
RRQ from 10.51.228.22 filename fixup4.dat
RRQ from 10.51.228.22 filename recovery.elf
RRQ from 10.51.228.22 filename config.txt
RRQ from 10.51.228.22 filename dt-blob.bin
RRQ from 10.51.228.22 filename recovery.elf
RRQ from 10.51.228.22 filename config.txt
RRQ from 10.51.228.22 filename bootcfg.txt
RRQ from 10.51.228.22 filename bcm2711-rpi-4-b.dtb
RRQ from 10.51.228.22 filename overlays/overlay_map.dtb
RRQ from 10.51.228.22 filename overlays/rpi-poe.dtbo
RRQ from 10.51.228.22 filename config.txt
RRQ from 10.51.228.22 filename overlays/vc4-fkms-v3d.dtbo
RRQ from 10.51.228.22 filename cmdline.txt
RRQ from 10.51.228.22 filename recovery8.img
RRQ from 10.51.228.22 filename recovery8-32.img
RRQ from 10.51.228.22 filename recovery7l.img
RRQ from 10.51.228.22 filename recovery7.img
RRQ from 10.51.228.22 filename recovery.img
RRQ from 10.51.228.22 filename kernel8.img
RRQ from 10.51.228.22 filename kernel8-32.img
RRQ from 10.51.228.22 filename kernel7l.img
RRQ from 10.51.228.22 filename armstub8-32-gic.bin
RRQ from 10.51.228.22 filename kernel7l.img
По первой строке можно заметить, что файлы начинают запрашиваться с префиксом, соответствующим серийному номеру платы. Если такая директория отсутствует, все остальные файлы запрашиваются из корня.
start4.elf и fixup4.dat — блоб и линкер, необходимые для инициализации видеоядра, так как GPU инициализируется еще до CPU.
сonfig.txt — файл с пользовательскими параметрами, влияющими на поведение прошивки EEPROM и инициализацию железа. Если проводить аналогию между eeprom и bios, в файле хранятся все настройки, измененные пользователем через графическое меню. Активные значения можно посмотреть через утилиту vcgencmd.
bcm2711-rpi-4-b.dtb — базовый файл, описывающий дерево устройств (device tree binary) на плате. Вообще тема DTB-файлов (и DTBO из папки overlays/) достойна отдельной статьи. В нашем контексте ограничимся, что это дерево впоследствии передается ядру Linux.
kernel8.img и cmdline.txt — ядро Linux, с которого начинается загрузка операционной системы. Через файл cmdline.txt передаются дополнительные параметры ядра.
В нашем случае, когда мы скопировали директорию /boot из установленной ОС, мы скопировали и файл cmdline.txt. Если просмотреть его содержимое, становится понятно почему, загружаясь по сети, мы попадали в установленную на SD-карту операционную систему.
cat cmdline.txt
console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait dwc_otg.lpm_enable=0
Опция root, которая указывает на корневую файловую систему, ведет на второй раздел SD-карты с ранее установленной Raspberry Pi OS.
Итоги и дальнейшие планы
Мы разобрались, как именно происходит загрузка по сети у Raspberry Pi 4. Осталось придумать, что в описанной схеме заменит загрузчик iPXE, через который мы управляем загрузкой сервера.
Стоп. А так ли нужно искать замену iPXE? Может, каким-то образом загрузить «малинку» сразу в iPXE?
Получилось ли у нас реализовать задуманное, я расскажу в следующей статье. А пока подписывайтесь на наш блог, чтобы не пропустить продолжение.