Установка системы с флешки на десяти машинах отнимает час и требует присутствия у каждой. Загрузка по сети переносит эту работу на один сервер: образы лежат в одном месте, меню собирается в текстовом файле, а установка идёт по кабелю без съёмных носителей. Разбираем устройство загрузки, файлы DHCP, разрыв цикла, сценарий меню и запуск установки Linux.
Из чего состоит цепочка загрузки
Сетевая загрузка начинается в прошивке адаптера. Встроенный PXE-клиент отправляет запрос DHCP, получает адрес и имя файла загрузки, скачивает его по TFTP и передаёт управление. Дальше либо запускается установщик напрямую, либо загружается более способная среда.
Штатный PXE-клиент работает только с TFTP, не понимает HTTP и не имеет средств выбора варианта. iPXE заменяет его и добавляет поддержку HTTP и HTTPS, работу с образами по сети, сценарии с условиями и меню. Отсюда схема, в которой штатный клиент загружает iPXE, а тот забирает остальное.
Цепочка выглядит так:
- Адаптер отправляет запрос DHCP и получает адрес, адрес сервера загрузки и имя файла;
- По TFTP скачивается образ iPXE, соответствующий типу прошивки, и получает управление;
- iPXE отправляет второй запрос DHCP и определяет, что клиент уже расширенный;
- Сервер выдаёт адрес сценария по HTTP, iPXE скачивает и исполняет его;
- Сценарий показывает меню либо сразу загружает ядро и начальный образ установщика;
- Установочная среда получает параметры и забирает остальные файлы по HTTP.
sudo mkdir -p /srv/tftp /srv/www/boot
ls -l /srv/tftp
На первом этапе удобно ограничиться одной машиной и одним вариантом загрузки: сначала убедиться, что адрес выдаётся и образ скачивается, и только потом добавлять меню и образы.
Каталог TFTP хранит загрузочные образы, остальное удобнее раздавать по HTTP: протокол быстрее и работает через кэш.
Файлы для BIOS и UEFI и различие архитектур
Тип прошивки определяет, какой образ загружать. Для BIOS применяют undionly.kpxe, он использует драйвер штатного PXE и совместим почти со всеми адаптерами. Для UEFI применяют ipxe.efi с собственным набором драйверов.
sudo wget -O /srv/tftp/undionly.kpxe http://boot.ipxe.org/undionly.kpxe
sudo wget -O /srv/tftp/ipxe.efi http://boot.ipxe.org/ipxe.efi
ls -l /srv/tftp
Различать клиентов сервер загрузки должен по параметру 93 запроса DHCP, в котором указан тип архитектуры. Значение 0 соответствует BIOS, значения 7 и 9 относятся к UEFI для 32 и 64 бит соответственно. По этому признаку и формируют ответ.
Загрузка по UEFI через сеть идёт медленнее, чем через BIOS: работа с сетевым стеком в этой прошивке устроена иначе. Скачивание крупного начального образа занимает минуты, поэтому большие файлы стоит забирать по HTTP, а не по TFTP.
В режиме совместимости UEFI-машина ведёт себя как BIOS-машина и запрашивает образ первого типа. Фактический режим виден по значению параметра 93 в журнале службы DHCP.
Как разорвать цикл повторной загрузки
После запуска iPXE отправляет новый запрос DHCP. Если сервер снова выдаст образ iPXE, среда будет загружать саму себя. Способов разорвать цикл три, выбирают тот, который удобнее поддерживать.
Первый способ, сценарий autoexec.ipxe рядом с образом: iPXE при старте скачивает и исполняет его. Способ прост, но поддерживается не всеми платформами.
Второй способ, различение клиентов по признаку: запрос от iPXE содержит параметр 175, которого нет у штатного PXE.
# dnsmasq: различение штатного PXE и iPXE
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:efi64,option:client-arch,7
dhcp-match=set:efi64,option:client-arch,9
dhcp-match=set:ipxe,175
pxe-service=tag:bios,X86PC,"iPXE for BIOS",undionly.kpxe
pxe-service=tag:efi64,BC_EFI,"iPXE for UEFI",ipxe.efi
dhcp-boot=tag:ipxe,http://192.168.10.5/boot/menu.ipxe
Параметр 175 присутствует только в запросах iPXE, и совпадение по нему означает, что клиент уже расширенный и ему нужно отдавать адрес сценария, а не образ.
Третий способ, встроить сценарий в образ при сборке. Вариант применяют, когда адрес сервера известен заранее: образ всегда загружает один сценарий независимо от настроек DHCP.
cat > /tmp/embed.ipxe <<'EOF'
#!ipxe
dhcp
chain http://192.168.10.5/boot/menu.ipxe
EOF
git clone --depth 1 https://github.com/ipxe/ipxe.git
cd ipxe/src && make bin/undionly.kpxe EMBED=/tmp/embed.ipxe
Сборка требует набора компилятора и занимает несколько минут. Поведение загрузки перестаёт зависеть от настроек DHCP, но образ придётся пересобирать при смене адреса.
Настройка службы DHCP и раздача файлов
Для небольшой сети удобнее dnsmasq, совмещающий раздачу адресов и службу TFTP.
# /etc/dnsmasq.conf
interface=eth0
bind-interfaces
dhcp-range=192.168.10.100,192.168.10.150,12h
dhcp-option=option:router,192.168.10.1
dhcp-option=option:dns-server,192.168.10.1
enable-tftp
tftp-root=/srv/tftp
dhcp-boot=undionly.kpxe,boot.example.local,192.168.10.5
Параметр dhcp-boot задаёт имя файла, имя сервера и его адрес. Достаточно имени файла, но адрес убирает неоднозначность в сетях с несколькими сегментами.
Когда адреса раздаёт другая служба, dnsmasq переводят в режим помощника: он не выдаёт адреса, а только дополняет ответы сведениями о загрузке.
# /etc/dnsmasq.conf в режиме помощника
port=0
interface=eth0
enable-tftp
tftp-root=/srv/tftp
dhcp-range=192.168.10.0,proxy
dhcp-boot=undionly.kpxe
pxe-prompt="Загрузка по сети",3
Значение port=0 отключает собственный DNS, dhcp-range с признаком proxy включает режим помощника, pxe-prompt задаёт задержку в секундах, в течение которой можно продолжить загрузку с диска.
Сценарии и образы раздаёт обычный веб-сервер, которому достаточно права на чтение каталога.
server {
listen 80;
server_name boot.example.local;
root /srv/www/boot;
autoindex on;
}
Журнал запросов DHCP включает опцией log-dhcp: в записях видно, какое имя файла и какой адрес сервера выданы клиенту. Если машины находятся в другом сегменте, запросы до сервера не доходят, поскольку широковещательный трафик не маршрутизируется, и помогает агент ретрансляции, которому указывают адрес сервера DHCP.
Проверка выполняется с рабочей машины: файл образа должен отдаваться по TFTP, а сценарий по HTTP.
curl -sI http://192.168.10.5/boot/menu.ipxe | head -n 3
sudo journalctl -u dnsmasq -f
Журнал службы показывает запросы и выданные файлы, и это основной инструмент при поиске причины отказа.
Сценарий iPXE и меню выбора
Сценарий это текстовый файл с командой на каждой строке. Первая строка объявляет формат, подстановки заключают в фигурные скобки, условия записывают через вопросительный знак после команды.
#!ipxe
dhcp
set base http://192.168.10.5/boot
:menu
menu Выбор загрузки
item --gap -- Установка систем
item install Установить Linux по сети
item rescue Загрузить среду восстановления
item local Загрузиться с локального диска
item shell Командная строка iPXE
choose --default local --timeout 10000 target && goto ${target}
:install
kernel ${base}/vmlinuz ip=dhcp root=/dev/nfs nfsroot=192.168.10.5:/srv/nfs/install rw
initrd ${base}/initrd.img
boot
:rescue
kernel ${base}/rescue/vmlinuz ip=dhcp
initrd ${base}/rescue/initrd.img
boot
:local
sanboot --no-describe --drive 0x80
:shell
echo Оболочка iPXE. Введите exit для перезагрузки.
shell
Команда menu описывает заголовок, item добавляет строки, choose показывает список и ждёт выбора. Параметр timeout задаёт ожидание в миллисекундах, после чего применяется значение по умолчанию, указанное в default. Метки вида :install служат целями перехода, команда goto выполняет переход, а конструкция с двойным амперсандом означает, что переход выполняется только при успешном выборе.
Команда sanboot передаёт управление загрузчику на указанном диске. Параметр no-describe отключает перечисление дисков, drive задаёт номер накопителя. Без перехода на локальный диск меню оказалось бы тупиковым для машин, которые нужно просто включить.
Выбор варианта связывают с адресом машины, чтобы разные группы получали разное поведение без отдельного сценария на каждую.
#!ipxe
dhcp
iseq ${net0/ip} 192.168.10.77 && set target install || set target menu
goto ${target}
Команда iseq сравнивает значение переменной с указанным и возвращает признак совпадения, что позволяет строить условия в одну строку.
Переменные iPXE содержат сведения из DHCP, и их удобно использовать для разных сценариев.
echo MAC: ${net0/mac} IP: ${net0/ip} arch: ${buildarch} platform: ${platform}
isset ${net1/ip} && echo Второй адаптер: ${net1/ip}
Проверка isset позволяет выдавать другой сценарий машинам из определённого диапазона адресов.
Запуск установки Linux по сети
Установочный образ состоит из ядра и начального образа корневой системы. iPXE загружает оба файла командами kernel и initrd, после чего boot передаёт управление. Параметры ядра задают способ получения адреса и расположение файлов.
#!ipxe
set repo http://192.168.10.5/repo/debian12
:debian
kernel ${repo}/linux auto=true priority=critical url=${repo}/preseed.cfg hostname=node1
initrd ${repo}/initrd.gz
boot
:rhel
kernel images/pxeboot/vmlinuz ip=dhcp inst.repo=http://192.168.10.5/repo/rhel9 inst.ks=http://192.168.10.5/boot/ks.cfg
initrd images/pxeboot/initrd.img
boot
Файлы берут из каталога установочного образа, скопированного на веб-сервер целиком. Для систем семейства Debian это файлы linux и initrd.gz, для семейства RHEL путь images/pxeboot с vmlinuz и initrd.img.
Параметры ядра различаются по семействам, смешивать их нельзя. Системы на основе Debian понимают параметр auto и адрес файла ответов в url, системы на основе RHEL используют префикс inst.
Автоматизация достигается файлом ответов: установщик читает его и не задаёт вопросов. Файл отдают по HTTP, и правки в нём не требуют пересборки загрузочных файлов.
curl -sI http://192.168.10.5/boot/ks.cfg | head -n 3
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.10.5/repo/debian/linux
Отдельно проверяют, что установщик получает адрес по сети: параметр ip=dhcp указывает ему запросить адрес самостоятельно, и при нескольких службах DHCP в сегменте результат может отличаться от ожидаемого.
Проверка доступности файлов до запуска экономит время: ошибка 404 на файле ядра выглядит в консоли как короткий список строк.
Диагностика, производительность и типичные ошибки
Оболочка iPXE доступна из меню или по сочетанию Ctrl+B при запуске. В ней команды выполняют по отдельности и видят текст ошибки.
ifstat
show net0/ip
imgfetch http://192.168.10.5/boot/menu.ipxe
imgstat
autoboot
Команда ifstat показывает счётчики пакетов. Команда imgfetch скачивает файл без исполнения, а imgstat перечисляет загруженные образы, что удобно для проверки доступности ядра до передачи управления.
Типичные ошибки сводятся к нескольким причинам. Машина не получает адрес, если служба DHCP не слушает нужный интерфейс либо запросы приходят из другого сегмента. Образ не скачивается при неверном пути или правах доступа к каталогу TFTP. Цикл возникает, когда сервер выдаёт iPXE в ответ на запрос от iPXE. Установка обрывается, если установщик не может забрать файлы, и причину видно по коду ответа.
Отдельная тонкость касается машин с проверкой подписи загрузчика: собранная самостоятельно версия iPXE подписи не имеет, и прошивка откажется её запускать.
Производительность упирается в TFTP на этапе первого файла. Образ iPXE небольшой, а начальный образ установщика в сотни мегабайт по TFTP идёт долго, поэтому крупные файлы держат на веб-сервере.
Проверяют также, что веб-сервер не требует аутентификации для каталога с образами: установка обращается к файлам без учётных данных.
Завершает настройку фиксация схемы: список файлов, их расположение, версия образа и содержимое сценария. Расхождение в поведении машин почти всегда объясняется различием прошивки, поэтому тип архитектуры из журнала DHCP стоит сохранять.