IPXE: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
 
Строка 4: Строка 4:
 
[[Категория:iPXE]]
 
[[Категория:iPXE]]
 
=iPXE=
 
=iPXE=
  +
* https://ipxe.org/cmd
 
* http://tdkare.ru/sysadmin/index.php/IPXE
 
* http://tdkare.ru/sysadmin/index.php/IPXE
 
* https://nefigtut.livejournal.com/28676.html?
 
* https://nefigtut.livejournal.com/28676.html?

Текущая версия на 15:21, 19 марта 2023

iPXE

Начальный сетевой PXE загрузчик iPXE

Внезапно, эта статья — продолжение предыдущих статей «Настройка PXE окружения» и «PXE-загрузка с использованием dnsmasq». Здесь я опишу начальный pxe-загрузчик (network bootloader) ipxe, который очень элитен и тот, кто в него умеет элитен также.


Некоторое отступление про ipxe. Вышеупомянутые статьи описывают что такое PXE и как оно вообще работает, если вы не — то читать. Одним из элементов PXE является начальный pxe-загрузчик, читаемый из ROM сетевой карты или по сети с TFTP-сервера. Его работа — загрузить с TFTP-сервера и отобразить загрузочное меню в каком-либо виде, загрузить выбранный код (например, ядро операционной системы) и запустить его. Этим он похож на MBR, которая только и делает, что находит активный загрузочный диск и читает с него загрузочный код. pxelinux.0 — довольно простой загрузчик, который умеет показать загрузочное меню в каком-то виде, загрузить выбранное по TFTP и запустить. gpxe — более продвинутый загрузчик, умеет в DNS, HTTP, iSCSI и подобное, появился как результат проекта Etherboot. ipxe — существенно переработанный форк gpxe, с собственной системой меню, команд и с поддержкой довольно экзотических протоколов, таких как AoE и HTTP. Что будет важно в следующей статье — он умеет san-boot, то есть умеет представлять LUN розданный по сети или с хранилища как локальный диск данной машины с доступом через функции BIOS-a. Это значит, что код, не имеющий понятия о сети или SAN, такой как GRUB или MSDOS, может видеть и иметь доступ к такому диску.


Для начала настроим простую конфигурацию PXE с ipxe и проверим, что она работает, чтобы в дальнейшем извращать всяко. Полигон для извращений следующий. Свежая минимальная инсталляция RHEL 6.6 с выключенными SELinux и файрволлом, которая будет работать как pxe-сервер. На этом сервере — три сетевых интерфейса, eth2 смотрит в интернеты, eth0 и eth1 — в локальную сеть. Есть инсталляционный диск с дистрибутивом RHEL 6.6, который мы собираемся устанавливать на другие сервера по PXE, диск смонтирован в, допустим, /media. Путь к корню TFTP-сервера — /var/lib/pxeboot, этот путь — произвольный, у нас будет такой.


Установим необходимый пакет dnsmasq для DHCP и TFTP сервера. В самом конце конфиг-файла /etc/dnsmasq.conf раскомментируем опцию conf-file, чтобы положить настройки относящиеся к PXE в отдельный файл /etc/dnsmasq.pxe.conf. Так же можно раскомментировать только опцию conf-dir и складывать конфиг-файлы с любым именем в каталог /etc/dnsmasq.d. Также установим всякую фигню, которая нужна, но не устанавливается в минимальной инсталляции.


[root@serv ~]# yum install dnsmasq wget man man-pages
[root@serv ~]# grep -v -e '^#' -e '^$' /etc/dnsmasq.conf
conf-file=/etc/dnsmasq.pxe.conf

Скачаем сам ipxe. В пакетах его нет, поэтому качаем с его сайта http://ipxe.org/ с вот этой страницы, вот ссылка на сам файл. Все ссылки рабочие на момент написания статьи, если что, вот локальная копия, билд dea6. Номер версии ipxe уже долгое время 1.0.0+, а номер патча/билда — начало id последнего коммита в git-репозитории проекта. Так что простого способа узнать какая версия старее или новее нет — надо клонировать себе git-репо ipxe и проверять какой коммит раньший.


[root@serv ~]# wget http://boot.ipxe.org/undionly.kpxe

Подготовим каталог /var/lib/pxeboot — корень TFTP-сервера.


[root@serv ~]# mkdir -p /var/lib/pxeboot/
[root@serv ~]# mv undionly.kpxe /var/lib/pxeboot/                       # первичный pxe-загрузчик ipxe
[root@serv ~]# cp /media/images/pxeboot/vmlinuz /var/lib/pxeboot/       # ядро Linux
[root@serv ~]# cp /media/images/pxeboot/initrd.img /var/lib/pxeboot/    # загрузочный ram-диск

Далее — конфиг dnsmasq, включающий DHCP и TFTP сервисы. Создадим простой конфиг-файл /etc/dnsmasq.pxe.conf с учётом того, что этому серверу статически назначены IP-адреса 12.0.0.10/24 и 13.0.0.10/24 на интерфейсы eth0 и eth1 (да, я знаю, что они белые и их, типа, нельзя использовать во внутренней сети, но мне пофиг).


[root@serv ~]# cat /etc/dnsmasq.pxe.conf
interface=eth0,eth1
dhcp-range=12.0.0.200,12.0.0.250,255.255.255.0,24h
dhcp-range=13.0.0.200,13.0.0.250,255.255.255.0,24h
enable-tftp
tftp-root=/var/lib/pxeboot
dhcp-boot=undionly.kpxe

После этого запускаем dnsmasq.


[root@serv ~]# service dnsmasq start
Starting dnsmasq:                                          [  OK  ]
[root@serv ~]# tail -30 /var/log/messages
Oct 66 66:00:03 serv dnsmasq[1266]: started, version 2.48 cachesize 150
Oct 66 66:00:03 serv dnsmasq[1266]: compile time options: IPv6 GNU-getopt DBus no-I18N DHCP TFTP "--bind-interfaces with SO_BINDTODEVICE"
Oct 66 66:00:03 serv dnsmasq-dhcp[1266]: DHCP, IP range 13.0.0.200 -- 13.0.0.250, lease time 1d
Oct 66 66:00:03 serv dnsmasq-dhcp[1266]: DHCP, IP range 12.0.0.200 -- 12.0.0.250, lease time 1d
Oct 66 66:00:03 serv dnsmasq-tftp[1266]: TFTP root is /var/lib/pxeboot
Oct 66 66:00:03 serv dnsmasq[1266]: reading /etc/resolv.conf
Oct 66 66:00:03 serv dnsmasq[1266]: using nameserver 66.66.66.66#53
Oct 66 66:00:03 serv dnsmasq[1266]: read /etc/hosts - 6 addresses

Пробуем загрузиться по PXE на втором сервере. Второй сервер должен запросить у dnsmasq-а IP и скачать по TFTP файл undionly.kpxe, вот что по этому поводу должны написать в лог:


[root@serv ~]# tail -30 /var/log/messages
Oct 66 66:21:43 serv dnsmasq-dhcp[1266]: DHCPDISCOVER(eth0) 66:66:66:66:66:66
Oct 66 66:21:43 serv dnsmasq-dhcp[1266]: DHCPOFFER(eth0) 12.0.0.200 66:66:66:66:66:66
Oct 66 66:21:45 serv dnsmasq-dhcp[1266]: DHCPREQUEST(eth0) 12.0.0.200 66:66:66:66:66:66
Oct 66 66:21:45 serv dnsmasq-dhcp[1266]: DHCPACK(eth0) 12.0.0.200 66:66:66:66:66:66
Oct 66 66:21:45 serv dnsmasq-tftp[1266]: TFTP sent /var/lib/pxeboot/undionly.kpxe to 12.0.0.200
Oct 66 66:21:45 serv dnsmasq-tftp[1266]: TFTP error 0 TFTP Aborted received from 12.0.0.200
Oct 66 66:21:45 serv dnsmasq-tftp[1266]: TFTP failed sending /var/lib/pxeboot/undionly.kpxe to 12.0.0.200
Oct 66 66:21:45 serv dnsmasq-tftp[1266]: TFTP sent /var/lib/pxeboot/undionly.kpxe to 12.0.0.200

На самом же втором сервере (PXE-клиенте) должны написать что-нибудь вроде:


CLIENT MAC ADDR: 66 66 66 66 66 66  GUID: 66666666-6666-6666-6666-666666666666
CLIENT IP: 12.0.0.200  MASK: 255.255.255.0  DHCP IP: 12.0.0.10
GATEWAY IP: 12.0.0.10
PXE->EB: !PXE at 9E55:0070, entry point at 9E55:0106
         UNDI code segment 9E55:0BDE, data segment 98BF:5960 (610-637kB)
         UNDI device is PCI 02:02.0, type DIX+802.3
         610kB free base memory after PXE unload
iPXE initialising devices...ok

iPXE 1.0.0+ (dea6) -- Open Source Network Boot Firmware -- http://ipxe.org
Features: HTTP iSCSI DNS TFTP AoE bzImage ELF MBOOT PXE PXEXT Menu

Press Ctrl-B for the iPXE command line...

Если написали что-то подобное, то ура, самое сложное сделано и кто-то внезапно не совсем неудачник и лузер. И теперь, если не нажать Ctrl-B происходит интересная штука — бесконечный цикл. А именно:



- Сетевая карта, умеющая в PXE (этот код расположен в её ROM), посылает в локальную сеть DHCP-запрос, получает IP и указание, что надо скачать c TFTP-сервера и запустить код из файла /var/lib/pxeboot/undionly.kpxe

- Сетевая карта скачивает этот код и передаёт ему управление

- Код из undionly.kpxe тоже запрашивает DHCP-сервер, получает IP и, внезапно, то же самое указание, что надо скачать и запустить /var/lib/pxeboot/undionly.kpxe

- Сервер застрял в бесконечном цикле, потому что ipxe, как сказано ему DHCP-сервером, загружает ipxe, который загружает ipxe, который угадайте что


Поэтому надо как-то сказать DHCP-серверу, чтобы он говорил PXE-клиенту загружать код ipxe (файл undionly.kpxe) только на первый DHCP запрос (от сетевой карты), а на DHCP запрос от самого ipxe говорил загружать что-то другое, например меню загрузки. К счастью, систему PXE и сам ipxe писали ни разу не идиоты, и такая возможность есть, так как ipxe добавляет в свой DHCP-запрос специальную опцию 175, наличие которой может проверить DHCP-сервер (ну, то есть, должен уметь, dnsmasq это умеет, какой-то другой DHCP-сервер, возможно, нет).


Итак, в файле /etc/dnsmasq.pxe.conf закомментируем строчку «dhcp-boot=undionly.kpxe» и напишем вот эти магические заклинания:


[root@serv ~]# cat /etc/dnsmasq.pxe.conf
...
# dhcp-boot=undionly.kpxe
dhcp-match=ipxe,175               # пометить запрос тэгом net:ipxe если в запросе была опция 175 (encapsulate ipxe)
dhcp-boot=net:#ipxe,undionly.kpxe # здесь #ipxe значит "не ipxe", то есть тэг не установлен
dhcp-boot=bootmenu.ipxe           # если тэг был установлен, сказать скачать этот файл

Не забыть сказать dnsmasq-у перечитать свой конфиг:


[root@serv ~]# service dnsmasq restart
Shutting down dnsmasq:                                     [  OK  ]
Starting dnsmasq:                                          [  OK  ]

Теперь при загрузке по PXE на втором сервере (PXE-клиенте) ipxe должен послать свой DHCP-запрос и после инициализации написать:


iPXE 1.0.0+ (dea6) -- Open Source Network Boot Firmware -- http://ipxe.org
Features: HTTP iSCSI DNS TFTP AoE bzImage ELF MBOOT PXE PXEXT Menu

net0: 66:66:66:66:66:66 using undionly on UNDI-PCI02:02.0 (open)
  [Link:up, TX:0 TXE:0 RX:0 RXE:0]
Configuring (net0 66:66:66:66:66:66)... ok
net0: 12.0.0.200/255.255.255.0 gw 12.0.0.10
Next server: 12.0.0.10
Filename: bootmenu.ipxe
tftp://12.0.0.10/bootmenu.ipxe... No such file or directory
No more network devices

Что ни разу не удивительно, потому что файла bootmenu.ipxe у нас как бы нет, но тем не менее, это значит, что внезапно кто-то чуть меньше неудачник. Поэтому напишем своё загрузочное меню ipxe, с которым будем далее извращаться. Начнём с простого: загрузка ядра и initrd RHEL 6.6:


[root@serv ~]# cat /var/lib/pxeboot/bootmenu.ipxe
#!ipxe

kernel vmlinuz
initrd initrd.img
boot

Так как это установочный initrd, после загрузки начнётся процесс установки RHEL 6.6. Разумеется для установки потребуются все остальные установочные файлы и для этого, разумеется, нужно будет поднять HTTP или NFS сервер, где они будут лежать, а инсталлятор сможет их оттуда взять. Здесь мы заниматься этим не будем, здесь мы играемся с ipxe, стремящимся пацанам смотреть раздел «Настройка HTTP и DNS-серверов для установки ОС используя kickstart» в статье «Настройка PXE окружения».


У ipxe адски крутая система команд, интересующимся смотреть документацию и примеры, особенно пример элитного загрузочного меню здесь (вот локальная копия). Здесь мы напишем простое меню, с загрузкой RHEL 6.6, memtest-a и, just for lulz, с загрузкой из интернетов. Для последней опции, разумеется интернеты должны быть на интерфейсе, на котором мы получили настройки IP по DHCP и сайт, предоставляющий этот сервис, должен работать и быть доступен. Memtest должен быть специальной версией http://boot.ipxe.org/memtest.bin (вот локальная копия), скачайте его и положите в /var/lib/pxeboot/.


[root@serv ~]# wget -O /var/lib/pxeboot/memtest.bin http://boot.ipxe.org/memtest.bin
[root@serv ~]# cat /var/lib/pxeboot/bootmenu.ipxe
#!ipxe

# Main menu
:start
menu Welcome to iPXE's Boot Menu
item
item install    Install RHEL 6.6
item memtest    Run Memtest86+
item inetboot   Boot Linux from the internets
item
item shell      Enter iPXE shell
item config     Enter iPXE config
item reboot     Reboot
item
item exit       Exit (boot local disk)
choose --default install --timeout 60000 target && goto ${target} || goto cancelled

# Utility menu items
:cancelled
echo Menu selection was cancelled
:shell
echo Type exit to get the back to the menu
shell
set menu-timeout 0
goto start

:failed
echo Booting failed, dropping to shell
goto shell

:config
config
goto start

:reboot
reboot

:exit
exit

# Menu items
:install
kernel vmlinuz
initrd initrd.img
boot

:memtest
kernel memtest.bin
boot

:inetboot
chain http://boot.ipxe.org/demo/boot.php

Теперь при загрузке по PXE на втором сервере должно показываться это меню и все его пункты должны, внезапно, работать, а если нет — то угадайте, что (подсказка: в ответе есть слово «неудачник»).