Что понадобится?
Совсем немного времени и трафика на скачивание нескольких небольших программ, а так же немного времени на
настройку (при наличии знаний по сетям). Помимо этого:
- Компьютер с Windows и сетевой картой (линейку 9х не проверял, но и с ней не должно быть проблем, а под NT
семейством и подавно). Как соединять два компа и настраивать сетку описывать не буду – и так много написано.
Априори считается, что вы можете соединить между собой два и более компа по сетке. - Компьютер, который будет загружаться по сети с наличием сетевой карты с поддержкой загрузки по сети (PXE)
- tftpd32 (вводим в Google и тыкаем на первую ссылку)
- pxelinux – часть пакета syslinux – (гуглим по “syslinux” или берем zip-архив тут)
- Программа для создания образа дискет. Например, WinImage
или что-то подобное. - рюмочка коньяка для храбрости 🙂
[править] что такое pxe?
PXE (англ. Preboot Execution Environment, произносится пикси) — среда для загрузки компьютеров с помощью сетевой карты без использования жёстких дисков, компакт-дисков и других устройств, применяемых при загрузке операционной системы.
Что получаем?
Компьютер грузится по сетке, подключается к вашему компьютеру, скачивает загрузчик и ждет вашего ввода команды. Ну
а там смотря что ввели:
Ну и далее только от фантазии зависит 🙂 Можно, например, известные утилиты от Paragon тоже так грузить, но это уже сложнее (надо выковыривать из загрузочных дисков ядра и
образы линукса), можно тот же thinstation terminal client и т.д.
Описание некоторых модулей syslinux
chain.c32 — переключает на следующий загрузчик (grldr, ntldr или просто на загрузчик, установленный на разделе HDD)reboot.c32 — перезагрузка компьютераmenu.c32 — при использовании в меню, может загружать дополнительные меню (подменю), или производить переход назад/между меню. Пример использования:
Перейдем к настройке
Создадим конфиг основного меню и внесем начальные настройки
ui vesamenu.c32
PROMPT 0
menu background background.jpg
menu title ServerClub PXE boot menu
LABEL bootlocal
menu label Boot from first HDD
kernel chain.c32
append hd0 0
timeout 120
TEXT HELP
The system will boot after the time is up
ENDTEXT
[править] /var/lib/tftpboot/ltsp/i386/pxelinux.cfg/default
Пример конфигурационного файла PXELINUX.
В этом примере в загрузке
есть три пункта меню:
- Ядро 2.4, без использованя framebuffer’а
- Ядро 2.6, с использованием framebuffer’а
- То же дополнительный параметр ядру, впоследствии доступный через /proc/cmdline
DISPLAY boot.msg TIMEOUT 300 PROMPT 1 LABEL 1 KERNEL vmlinuz-2.4.34.lan APPEND root=/dev/nfs rw nfsroot=192.168.15.244:/opt/ltsp/i386/ ip=dhcp LABEL 2 KERNEL vmlinuz-2.6.19.2 APPEND root=/dev/nfs rw nfsroot=192.168.15.244:/opt/ltsp/i386/ ip=dhcp vga=792 LABEL 3 KERNEL vmlinuz-2.6.19.2 APPEND root=/dev/nfs rw nfsroot=192.168.15.244:/opt/ltsp/i386/ ip=dhcp vga=792 rescue-ata-flash
/home/rdp/.xsession
[править] инсталляция dhcp-сервера
Установка DHCP-сервера:
%# apt-get install dhcp . . . NOTE: dhcpd's messages are being sent to syslog. Look there for diagnostics messages. Starting DHCP server: dhcpd failed to start - check syslog for diagnostics.
DHCP-сервер не заработал в базовой конфигурации – смотрим почему:
%# tail /var/log/daemon.log Dec 25 17:27:56 debian rpc.statd[4128]: Version 1.0.10 Starting Dec 25 17:33:43 debian dhcpd: No subnet declaration for eth0 (192.168.15.244). Dec 25 17:33:43 debian dhcpd: Please write a subnet declaration in your dhcpd.conf file for the Dec 25 17:33:43 debian dhcpd: network segment to which interface eth0 is attached. Dec 25 17:33:43 debian dhcpd: exiting.
Анализ лог-файла /var/log/daemon.log говорит, что не описана сеть 192.168.15.0/24.
Указанная сеть была определена автоматически, исходя из адреса
интерфейса, на котором DHCP-сервер прослушивает запросы.
По умолчанию этот интерфейс eth0.
Конфигурационный файл dhcpd.conf не содержит описания этой сети.
Ниже мы отредактируем этот файл и опишем в нём названную сеть.
Если бы было нужно чтобы DHCP-сервер работал на другом интерфейсе,
нужно отредактировать файл /etc/default/dhcp —
указать нужный интерфейс:
%# vim /etc/default/dhcp INTERFACES="eth1"
Сейчас этого делать не нужно.
[править] настройка tftp-сервера
В момент завершения установки нам было сообщено о том, что TFTP-сервер по-умолчанию не работает в режиме демона, а будет запускаться через интернет-суперсервер inetd. Проверим на наличие строки его настройки в конфигурационном файле inetd:
%# grep tftp /etc/inetd.conf tftp dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /var/lib/tftpboot
Перезапустим интернет суперсервер:
%# /etc/init.d/inetd restart Restarting internet superserver: inetd.
И проверим выполняет ли интернет-суперсервер
прослушивание порта 69 (порт TFTP):
%# netstat -lnp | grep :69 udp 0 0 0.0.0.0:69 0.0.0.0:* 7331/inetd
На этом настройка TFTP-сервера завершена.
Я установил TFTP-server (apt-get install tftp-server), который умеет работать в режиме демона, запускается он так:
%# in.tftpd -l -s /var/lib/tftpboot
[править] создание “базовой площадки”
Для работы операционки все необходимые файлы можно разбить на 3 категории:
- изменяемые сохраняемые (/home …);
- изменяемые не сохраняемые (/etc /var/log /var/run …);
- неизменяемые (все прочие).
Мы создадим “базовую площадку”, которая инициализирует файловую систему с учётом вышеописанных принципов. Для упрощения, корневую файловую систему разместим в /ltsp
Для начала экспортируем всё необходимое.
Затем возьмём за основу содержимое локального initrd.img.
Мы экономить не будем, а поэтому закинем необходимые бинарники, а позже библиотеки к ним.
Так же возьмём busybox в качестве шелла — вы сможете использовать /bin/ash в /init для отладочных целей.
Так же нам необходима часть его функций для развёртывания.
ifconfig нам нужен только для того, чтобы убедится в правильности назначения IP-адреса ядром.
С помощью mount.nfs будем монтировать необходимое для работы, т.к. больше ничто не может нормально работать с nfs. Так же нам необходим FIFO-файл initctl в каталоге устройств для “общения” с init’ом.
# mkdir /ltsp; # cat >> /etc/exports /ltsp/ *(ro,no_root_squash,async,no_subtree_check) /usr/ *(ro,no_root_squash,async,no_subtree_check) /var/ *(ro,no_root_squash,async,no_subtree_check) /lib/ *(ro,no_root_squash,async,no_subtree_check) /bin/ *(ro,no_root_squash,async,no_subtree_check) /sbin/ *(ro,no_root_squash,async,no_subtree_check) # /etc/init.d/nfs-server restart # cd /ltsp # gzip -cd /boot/initrd.img | cpio -imd --quiet # cp `which busybox` /ltsp/bin # cp `which ifconfig` /ltsp/bin # cp `which mount.nfs` /ltsp/bin # cp `which init` /ltsp/bin # cd /ltsp/bin # ln -s busybox ash # ln -s busybox ln # ln -s busybox tar # ln -s busybox gunzip # ln -s busybox cat # ln -s busybox mount # ln -s busybox pivot_root # mknod /ltsp/dev/initctl p
Проверить, какие библиотеки используют скопированные бинарники можно командой ldd (ldd /sbin/ifconfig). У меня получилось всего 2:
cp /lib/ld-linux.so.2 /ltsp/lib cp /lib/libc.so.6 /ltsp/lib
/sbin/init запускается первым и остаётся первым всё время. При своём запуске он читает inittab, секцию sysinit. там у нас указано выполнение нашего /init. Это сделано, по большей части, для удобства редактирования.
При загрузке необходимы “свои” конфигурационные файлы. “Выстрелим из бочки” и cнимем копию с рабочей системы скопировав /etc, подправим его. Оригинальный inittab заменит наш файл и загрузка продолжится в исходном режиме. Для уменьшения размеров и ускорения его загрузки по сети, запакуем его и будем распаковывать при каждой загрузке. Так же при загрузке у нас уже, наверняка, будет сконфигурирована сеть, поэтому удалим соответствующие файлы.
[править] создание клиентского образа ltsp
Образ создаётся с помощью скрипта ltsp-build-client.
В качестве аргументов скрипту необходимо указать:
- архитектуру, для которой выполняется сборка;
- дистрибутив, на базе которого будет построен образ;
- зеркало, с которого должны инсталлироваться пакеты системы.
В каталог, который будет для бездисковой станции корневым,
проинсталлируется дистрибутив etch.
В качестве источника пакетов указан локальный apt-proxy.
Вместо него нужно указать соответствующее зеркало.
1. Разделы и файловые системы
Я люблю и уважаю LVM за его гибкость и удобство в работе, поэтому использую сетап, не требующий таблицы разделов на образе client. Вместо этого сразу на client создаётся еще одна VolumeGroup, которая потом режется на lv-тома.
root@target:~# pvcreate /dev/mapper/vg00-client
Physical volume "/dev/mapper/vg00-client" successfully created
root@target:~# vgcreate client /dev/mapper/vg00-client
Volume group "client" successfully created
root@target:~# lvcreate -L 12G -n rootfs client
Logical volume "rootfs" created
root@target:~# lvcreate -l 100%FREE swap client
Logical volume "swap" created
Создадим файловую систему и разметим раздел под swap:
root@target:~# mkfs.ext4 /dev/mapper/client-rootfs
root@target:~# mkswap /dev/mapper/client-swap
3. Сохранение настроек
Несмотря на то, что действия в targetcli выполняются немедленно, они не сохраняются и после перезагрузки все таргеты не вернутся. В этом поведение LIO похоже на поведение любых других ядерных служб (iptables, ebtables, ipvsadm и т. п.). При сохранении настроек targetcli компилирует всю конфигурацию в shell-скрипт, который просто скармливает нужные данные в configFS.
Сохраним все настройки:
cd /
saveconfig
Таргет готов! Перейдем к настройке DHCP TFTP.
DHCP-сервер
Предполагаем следующую конфигурацию:
Серверы живут в сети 10.0.0.0/24, таргет живет на 10.0.0.2, клиент получает по DHCP адрес 10.0.0.5.
Мануалов в сети море, поэтому коротко:
root@target:~# aptitude install -y isc-dhcp-server
dhcpd.conf:
allow booting;
allow bootp;
subnet 10.0.0.0 netmask 255.255.255.0 {
range 10.0.0.10 10.0.0.254;
option broadcast-address 10.0.0.255;
option routers 10.0.0.1;
option domain-name-servers 8.8.8.8;
filename "/pxelinux.0";
}
host client {
hardware ethernet XX:XX:XX:XX:XX:XX; # Тут должен быть MAC-адрес сетевой карты client'а
fixed-address 10.0.0.5;
}
Стартуем демон:
root@target:~# /etc/init.d/isc-dhcp-server start
Syslinux
Устанавливаем пакет:
root@target:~# aptitude install -y syslinux syslinux-common
Копируем pxelinux.0 в /var/lib/tftpboot:
root@target:~# cp /usr/lib/syslinux/pxelinux.0 /var/lib/tftboot
Также нам необходим образ ядра (можно взять с хост-системы). Сейчас у меня используется ядро от Ubuntu версии 3.2.0.37:
root@target:~# cp /vmlinuz /var/lib/tftboot/vmlinuz-3.2.0-37-generic
Дальше нужно собрать правильный initramfs. Для этого нам нужен модуль iSCSI:
Example
would this be better to just exist in specific model’s wiki pages?
should we create a page to list models with tftp support, noting which ones need the reset button trick?
On many routers, including the Asus WL-500g Premium v1 that I use, you flash an image by disconnecting power, press and hold down the reset button, and connect the power again. Wait a few seconds and the PWR LED will start to blink. Release the reset button. The device will now have a TFTP server running on 192.168.1.1
.
Note that many TP-Link models are reported to support the same trick, including the TL-WR740Nv4, TL-WDR4300v1, TL-WDR3600v1, TL-WR842NDv1, TL-WR841NDv8, TL-WR841Nv11, TL-WR841Nv12, TL-MR3020v1, TL-MR3220v2, TL-MR3420v2, TL-WR940Nv2, TL-WR941NDv5, TL-WR1042NDv1 and possibly any other TP-Link model that has a recent firmware upgrade from the manufacturer. For a summary and ongoing experiments, see: http://bkil.blogspot.com/2022/12/hidden-tftp-of-tp-link-routers.html
You’ll have to use a Ethernet cable at this point. Connect it to LAN1-LAN4, notWAN. Configure your local machine on the 192.168.1.x/24
network, for example as 192.168.1.42
. The router will use 192.168.1.1
.
$ tftp 192.168.1.1 tftp> trace Packet tracing on. tftp> binary tftp> put openwrt-brcm-2.4-squashfs.trx sent WRQ <file=openwrt-brcm-2.4-squashfs.trx, mode=octet> received ACK <block=0> sent DATA <block=1, 512 bytes> received ACK <block=1> sent DATA <block=2, 512 bytes> received ACK <block=2> sent DATA <block=3, 512 bytes> received ACK <block=3> sent DATA <block=4, 512 bytes> ... received ACK <block=4742> sent DATA <block=4743, 512 bytes> received ACK <block=4743> sent DATA <block=4744, 512 bytes> received ACK <block=4744> sent DATA <block=4745, 0 bytes> received ACK <block=4745> Sent 2428928 bytes in 6.2 seconds tftp> quit $
Wait one minute and restart the box by disconnecting and reconnecting power. Some documentations claim that the device should restart by itself but I have never seen this happen, no matter how long I wait.
Iscsi-таргеты
iSCSI — реализация протокола SCSI поверх TCP. Сам протокол SCSI весьма универсален, теоретически с его помощью можно подключить устройство любого типа. Тем не менее, в большинстве случаев SCSI используется для доступа к тем или иным устройствам хранения данных (жёсткие диски, приводы CD и DVD и т. п.). Для примера Mass Storage Device, использующийся в USB-устройствах, является реализацией SCSI поверх USB. Поэтому, кстати, флешки в Linux опознаются как /dev/sdX-устройства. Использующаяся на серверах шина SAS также является реализацией SCSI (собственно, это видно из названия — Serial Attached SCSI).
В iSCSI различаются понятия таргета (target, целевое устройство, осуществляет приём и выполнение запросов) и инициатора (initiator, порождает запросы). В более привычных терминах таргет — это сервер, а инициатор — клиент.
Таргеты и инициаторы бывают разных видов. iSCSI-таргетом может выступать обычный компьютер, сервер или система хранения данных. Инициаторами обычно выступают сетевые карты (в их ROM бывает прошит необходимый код) или software-реализации.
Для Ubuntu возможно использовать различные iSCSI-таргеты. Вот неполный их список:
Using tftpd-hpa
A detailed guide for beginners to tftpd-hda
There are multiple tftp clients that you can choose from.
Автоматическая установка и оптимизация nextcloud 21 (nginx, mariadb)
Скрипт поддерживает установку в операционных системах Debian 10.8 (AMD64) и Ubuntu 20.04.1 (AMD64). Для работы скрипта необходима установка пакета sudo.
Рассматривается установка на чистую систему, в которой не установлены другие инструменты, необходимые для веб-приложений.
В ходе работы скрипта будут подключены следующие репозитории для использования последних версий пакетов: ppa ondrej для установки php 7.4, ppa mainline для установки последней версии nginx, а так же репозиторий mariadb для установки MariaDB 10.5.
Важно. В качестве домена скрипт укажет имя хост системы . Поэтому перед началом работы скрипта, измените имя хоста системы и перезагрузите систему.
Имя хоста можно поменять следующим образом:
Есть и минусы
- У tftpd32 есть баг – при одновременном обращении к нему больше одного клиента – жуткие тормоза на этапе
загрузки pxelinux’а и образов. Если кому-то надо грузить, скажем, сразу много клиентов, то tftpd32 придется оставить
только как DHCP, убрав в настройках галочку про TFTP Server (если, конечно, нет другого DHCP), а сам TFTP сервер взять другой (к сожалению, те
серверы что я видел – коммерческие). Однако, при последовательном обращении клиентов – все летает. Так что как
вариант просто грузить компы по очереди.
Загрузка hiren’s boot cd
Для версии 9.9 нужно скопировать в каталог загрузки файл hiren.ima из образа диска, а так же pxelinux.0 и memdisk из syslinux. Конфиг загрузки
DEFAULT memdisk APPEND floppy c=35 h=64 s=32 initrd=hiren.ima
Подробно тут
История
Однажды к нам пришли (ну, не сами…) серверы с 14 хардами по 2Тб. Избавившись от аппаратного рейда (зачем — вопрос отдельный), мы задумались о том, что неплохо бы сделать для них загрузку по сети, дабы избавиться от возни с разделами. Диски предполагалось экспортировать по iSCSI, и не хотелось выделять какие-то диски на Особенные Системные Диски, а какие-то на всё остальное. Таким образом возникла задача сделать загрузку по сети с размещением корневого каталога в оперативной памяти.
Конфигурируем tftpd32.exe
Запустили, нажали Settings, в “страшном” окне указываем Base Dirrectory – C:TFTP. Потом выставляем галочки как на
картинке:
Жмем на ОК, еще раз ОК, и перезапускаем tftpd32.
Далее настраиваем наш DHCP сервер:
- Выбираем сетевую карточку, к которой подключен пациент
- Ставим начало адресов, которые получит первый клиент (этот адрес и количество клиентов не должно пересекаться с
вашим IP) - Количество адресов (минимум 1)
- Имя загрузчика (pxelinux.0)
- Маска сети (мат-часть по сетям)
- Сохраняемся….
Далее на всякий случай перезапускаем tftpd32. Почти закончили 🙂
Конфигурируем загрузку
Создаем текстовый файл C:TFTPPXELINUX.CFGdefault и редактируем его, скажем, так:
default local prompt 1 label local localboot 1 label dos kernel memdisk append initrd=dos.imz label pqpm8 kernel memdisk append initrd=pqpm8.imz label mem kernel memtest
Подробную информацию можно найти в pxelinux.doc из syslinux’a.
Ну и наконец, устанавливаем на компе загрузку с сетевого адаптера по PXE.
Настраиваем загрузку по сети с помощью grub
Поскольку GRUB на нашем сервере уже есть, создадим с его помощью структуру папок для сетевого клиента вот таким образом:
grub-mknetdir --net-directory=$root/boot --subdir=grub
В папке $root/boot появится папка grub и несколько других. Эту файловую структуру мы будем целиком «отдавать» с помощью TFTP-сервера. Сейчас мы используем 64-битный ArchLinux по той причине, что в 32-битной системе нет папки /grub/x86_64-efi/, которая требуется для загрузки систем UEFI.
Создайте файл конфигурации загрузчика со следующим содержимым:
Я взял файл grub.cfg с сервера и убрал из него всё то, что не участвует в отображении загрузочного меню GRUB или как-то связано с дисками.
Обратите внимание на знакомую нам строку с параметрами ядра:
linux /vmlinuz-linux add_efi_memmap ip="$net_default_ip":"$net_default_server":192.168.1.1:255.255.255.0::eth0:none nfsroot=${net_default_server}:/diskless
Как и в
присваиваем значение переменной «ip». Напоминаю, что она используется в обработчике «net», который мы приспособили для настройки сетевой карты в загрузочном сервере. Здесь снова указывается статический IP адрес и постоянное имя сетевой карты eth0. Значения $net_default_ip и $net_default_server подставляются GRUB самостоятельно на основании данных, полученных из самого первого DHCP запроса. $net_default_ip – это выделенный для нашей машины IP адрес, а $net_default_server — IP адрес загрузочного сервера.
Большинство руководств по сетевой загрузке (среди обнаруженных на просторах рунета), предлагают устанавливать переменную так «ip=::::::eth0:dhcp», что вынуждает обработчик net отправлять новый запрос DHCPDISCOVER для повторного получения сетевых настроек.
Нет объективной причины лишний раз «спамить» DHCP-сервер и ждать, пока он откликнется, поэтому снова используем статику и не забываем указать DNS-серверы. Такую задачу мы уже решали, поэтому просто копируем нужные файлы и добавляем службу в автозагрузку:
cp {,$root}/etc/systemd/system/update_dns@.service && cp {,$root}/etc/default/dns@eth0 && arch-chroot $root systemctl enable update_dns@eth0
Возвращаемся к строке с параметрами ядра. Ещё незнакомая нам команда add_efi_memmap (EFI memory map) добавляет EFI memory map доступной RAM. В прошлый раз мы её намеренно пропустили, из-за сравнительно сложной предварительной разметки носителя для поддержки UEFI.
Переменная ядра — nfsroot показывает, где именно в сети нужно искать корневую файловую систему. Она выполняет ту же самую функцию, что и переменная root в загрузочном сервере. В данном случае указан адрес NFS-сервера, который в нашем случае совпадает с TFTP-сервером, но это совершенно необязательно.
Настройка dhcp на cisco
network <ip сети> <маска>
ip dhcp pool <Имя пула>
bootfile pxelinux.0
next-server <IP сервера tftp>
default-router <Шлюз>
option 66 ascii «Имя сервера»
dns-server <DNS сервера>
option 150 <IP сервера tftp>
domain-name <доменное имя>
Настройка tftp сервера
Более подробно можно прочитать в статье установка TFTP-hpa сервера или настройка Настройка TFTP сервера на Mikrotik RouterOS
Настройка сетевого загрузчика pxe на syslinux
На самом деле, загрузчик SYSLINUX — это целый комплекс загрузчиков, на все случаи жизни, здесь есть и сетевой — PXELINUX, и загрузчик для ISO-образов ISOLINUX и просто загрузчик ОС с жесткого диска. Пока нам потребуется только сетевой. SYSLINUX представляет собой операционную систему в миниатюре, загрузчик с помощью специальных команд, прописываемых в загрузочном меню, может выполнять специальные функции, сохраняемые в исполняемых файлах особого формата — модулях загрузчика.
Начнем с плюсов моего метода
- Не надо иметь выделенный RIS сервер (вообще не надо сервер) – не всегда он есть под рукой, а иногда за него
надо платить… - Грузить можно любой 1.44, 2.88 и 5.76 (ага, и такие бывают!) образ дискеты как он есть, без изменений
(единственное если прога на 2-х дискетах 1.44, то ее надо слить в один образ 2.88), плюс образ любого размера,
который поместится в память клиента (речь уже об образе диска, а не дискеты) - Можно грузить различные линуксы, которые работают с RAM диска (например, thinstation – это RDP клиент, или те же
утилиты от Paragon) - Можно грузить различные линуксовые бинарники (например memtest86 )
- Легко модифицировать любую сеть для такой работы. Надо всего лишь на DHCP сервере сети указать IP нашего PXE
сервера и имя загрузчика. Это в моей статье не описывается, так как уже было описано в первой статье (два параметра для DHCP – 066, 067), и админам думаю проблем не составит сделать нужные
изменения) - Можно все нужные файлы таскать с собой на Flash диске – и тогда любой комп быстро превращается в PXE сервер
(только надо перенастроить в tftpd32 – путь к файлам и IP адреса, и перезапустить его)
Несколько слов о конфиге pxelinux
В корне tftp-сервера размещается загрузчик pxelinux.0. Для его конфигурирования используется один из файлов в каталоге pxelinux.cfg. Таким образом, полный путь к каталогу конфигов загрузки /var/lib/tftpboot/pxelinux.cfg.
Загрузчик будет пытаться прочитать свой конфиг, перебирая имена файлов в следующем порядке:
- 1905cddb-18f7-4f21-a91c-3daee3408bee – имя соответствует GUID клиентского компьютера
- 00-23-8B-82-42-F2 – имя соответствует MAC-адресу компьютера
- C0A80063 – с именем, соответствующим IP-адресу (в данном случае 192.168.0.99) в шестнадцатиричном представлении
- C0A8006, C0A800….C0, C – с именем, соответствующим части IP-адреса в шестнадцатиричном представлении
- default – дефолтовый
Если файл не найден, то загрузчик перезагрузит компьютер через некоторое время.
Документация по PXELINUX (на английском)
Подготовка сервера dhcp
Файл /etc/dhcp/dhcpd.conf
В секции host должна присутствовать запись filename, указывающая на файл для начальной загрузки. Кроме того, можно добавить запись next-server – IP-адрес сервера загрузки, если он не совпадает с адресом сервера DHCP. Так же, могут быть указаны опции. Пример секции конфигурирования хоста:
host vk-nout { hardware ethernet 00:23:8B:82:42:F2; fixed-address 192.168.0.99; next-server 192.168.0.100; filename "/pxelinux.0"; }
Поехали!
- Распаковываем tftpd32.exe, скажем, в С:TFTP
- Распаковываем файл pxelinux.0 (из архива syslinux’а), memdisk (из sysylinux.zip/memdisk) а
так же (опционально) memtest (sysylinux.zip/memtest) в C:TFTP. - Tуда же (C:TFTP) кладем образ любимой загрузочной дискетки (можно и не только дискетки – но об этом ниже).
Например, dos.imz (для экономии места и/или ускорения загрузки можно даже сжатый (winimage) образ класть –
imz, a можно и не сжатый ima). Образов может быть сколько угодно. - Проверяем, что у нас в сети нету DHCP серверов. Например, если включен ICS (шара интернета), то его выключить
на время экспериментов.
Послесловие
В статье делается упор на tftpd32, так как он бесплатен, не требует установки, и включает в себя 2 сервера в 1 (DHCP и TFTP), а также запускается под Windows любой версии. Но сам принцип – загрузка и запуск бинарника pxelinux (с последующей загрузкой нашего образа) – не привязан к tftpd32, а требует наличия в сети DHCP сервера с двумя дополнительными параметрами – 067 (имя загружаемого бинарника – pxelinux.0)
и 066 (IP адрес TFTP сервера который нам и выдает искомый бинарник), а также собственно TFTP сервер, на который ссылается DHCP. Какими системами, сервисами или железками это реализовано нам совершенно неважно, потому можно использовать любой находящийся в сети сервер (Linux, Windows, Novell). Ну а если его нет, то tftpd32, запущенный на любой машине. Главное – это добраться по сети до PXELINUX.
Предисловие
Прочитал статью с описанием способа RIS и решил поделится своим методом. Дело в том что по работе
мне приходится часто кидать образы на компьютеры в школах, к которым у детишек отношение весьма не доброе, а потому
большинство CD-ROM сломано, а с дисководом никогда не угадаешь заранее, считает дискетку или нет. Поэтому загрузка образов
дискет (и не только) через PXE мне очень близка.
Пробуем загрузиться по сети
Проследим за процессом загрузки с сервера с помощью программы tcpdump
pacman -S tcpdump
tcpdump -v '(
src host 0.0.0.0 and udp[247:4] = 0x63350101) or (
dst host HabraBoot and dst port tftp) or (
dst host HabraBoot and tcp[tcpflags] == tcp-syn)'
Первая строка «ловит» запрос DHCPDISCOVER от PXE клиента. В выводе, отфильтрованном второй строкой, будут перечислены имена всех файлов, запрашиваемых по TFTP. Третья строка показывает два tcp-syn запроса, отправляемых в самом начале подключения по протоколу NFS (первое соединение осуществляется обработчиком net, а второе переподключение происходит во время обработки файла fstab).
Создаём новую виртуальную машину, для краткости будем называть её «клиент». В настройках сети снова указываем тип подключения «Сетевой мост» и включаем машину. Сразу же нажимаем клавишу F12 на клавиатуре для выбора загрузочного устройства, а потом клавишу l, чтобы загрузиться по сети.
Дождитесь окончания загрузки. Если всё в порядке, то на сервере добавляем используемые службы в автозагрузку:
systemctl enable tftpd.socket tftpd.service dhcpd4 rpcbind nfs-server
Все серверы DHCP, TFTP и NFS мы запустили на одном загрузочном сервере. Делать так необязательно. Например, роутеры Mikrotik поддерживают Bootp и позволяют использовать себя в качестве TFTP — просто закачайте туда все нужные файлы и проверьте сетевые настройки.
Сейчас графическое окружение будет работать только в VirtualBox, потому что мы не устанавливали драйверы для «железных» видеокарт. Мы решим проблему автоматического подбора нужных драйверов в следующей статье. Заодно ускорим загрузку системы и сделаем из неё «живой образ».
Снова устанавливаем linux
Archlinux выгодно отличается от готовых дистрибутивов тем, что установка новой системы из рабочей машины осуществляется точно так же, как при использовании установочного образа, и в обоих случаях вы получаете самую актуальную на данный момент версию системы. Понадобятся лишь небольшие установочные скрипты:
pacman -S arch-install-scripts
Совершенно предсказуемое начало:
export root=/srv/nfs/diskless
mkdir -p $root
Установим только базовые пакеты, поэтому:
pacstrap -d -c -i $root base
Далее повторите все действия вплоть до установки загрузчика согласно предыдущей статье. Вот чек-лист:
Сравним загрузку с диска и загрузку по сети
В предыдущей статье мы рассматривали процесс загрузки Linux с точки зрения внутреннего накопителя. Сейчас мы представим происходящее глазами сетевой карты. Картинка из заголовка хорошо иллюстрирует события за исключением того, что все серверы в нашем случае будут работать на одном компьютере.
Сразу после включения компьютера, срабатывает код PXE (Preboot eXecution Environment, произносится пикси — спасибо вики), разместившийся непосредственно в ПЗУ сетевой карты. Его задача — найти загрузчик и передать ему управление.
Сетевой адаптер совершенно не представляет в какой сети сейчас находится, поэтому назначает себе адрес 0.0.0.0 и отправляет сообщение DHCPDISCOVER. К сообщению прикреплются паспортные данные, которые обязательно нам пригодятся:
Адаптер ожидает получить ответ от DHCP сервера по протоколу BOOTP (Bootstrap Protocol), где помимо нужного IP адреса, маски подсети и адреса шлюза, присутствует информация об адресе TFTP-сервера и названии файла загрузчика, который с него следует забрать. Сервер TFTP, в свою очередь, просто отдаёт любому желающему любые файлы, которые у него попросят.
После получения ответа и применения сетевых настроек, дальнейшее управление загрузкой передаётся полученному файлу, размер которого не может превышать 32 кБ, поэтому используется двухстадийная загрузка. Всё необходимое для отображения на экране загрузочного меню докачивается следом по тому же протоколу TFTP.
Далее загрузка приостанавливается на время отображения загрузочного меню, а потом по тому же протоколу TFTP докачиваются выбранные файлы vmlinuz и initramfs, которым передается дальнейшее управление загрузкой. На этом этапе уже нет вообще никакой разницы в механизме загрузки по сети или с внутреннего накопителя.
Устанавливаем dhcp сервер
Скачиваем пакет:
pacman -S dhcp
и приводим содержимое конфигурационного файла /etc/dhcpd.conf к следующему виду:
mv /etc/dhcpd.conf /etc/dhcpd.conf.old
# Разрешаем использование протокола BOOTP
allow booting;
allow bootp;
# Утверждаем, что сервер является авторитетным (обычно роутеры либо не авторитетны, либо BOOTP не поддерживают, поэтому их PXE слушать не будет)
authoritative;
# получаем архитектуру клиента (это обсуждалось выше)
option architecture code 93 = unsigned integer 16;
# работаем в такой подсети (исправляйте под себя)
subnet 192.168.1.0 netmask 255.255.255.0 {
# в этот класс попадут все те, кто пытается загружаться
class "pxe_client" {
match if exists architecture;
}
pool {
# Разным архитектурам отдаём разные файлы:
if option architecture = 7 {
filename "/grub/x86_64-efi/core.efi";
} else {
filename "/grub/i386-pc/core.0";
}
# Рекомендую указать адрес TFTP сервера, несмотря на то, что это необязательно, раз он там же, где DHCP
next-server 192.168.1.100;
# Здесь, как обычно (не забывайте исправлять под себя)
default-lease-time 600;
max-lease-time 7200;
option domain-name-servers 192.168.1.1;
option routers 192.168.1.1;
range 192.168.1.128 192.168.1.192;
# Обрабатываем запросы только тех, кто загружается
allow members of "pxe_client";
}
}
Как видите, DHCP-сервер будет отвечать только на те запросы DHCPDISCOVER, которые придут от PXE клиентов, а остальные просто проигнорируются.
Запускаем DHCP сервер:
systemctl start dhcpd4
Устанавливаем tftp сервер
Скачиваем и устанавливаем необходимый пакет:
pacman -S tftp-hpa
Нам нужно, чтобы TFTP сервер предоставлял доступ к файлам загрузчика, которые мы разместили в папке $root/boot. Для этого модифицируем запуск службы уже проверенным способом:
Итоги:
Можно вполне использовать iSCSI для загрузки серверов, не имеющих своих дисков (актуально для виртуализации, самопильных систем хранения данных, серверов, которые не должны долго жить и т.п.).
Есть другой вариант, использовать инициатор, встроенный в сетевую карту. Такой подход иногда бывает невозможен по различным причинам (самая банальная — отсутствие необходимого функционала в самой карточке), а также обладает несколько меньшей гибкостью.
Присутствует security-hole, поскольку /proc/cmdline доступен любому желающему в системе и этот любой желающий может получить доступ к экспортированному тому. Поэтому можно на таргете закрыть фаерволом все адреса, кроме необходимого.
Описанная схема — по большей части драфт и основа для инфраструктуры сетевой загрузки.
Подготавливаем initramfs
За подключение корневой файловой системы по протоколу NFS отвечает обработчик net. В прошлый раз мы убирали из него эту функциональность, но сейчас она нам понадобится, правда, в немного доработанном виде. Дело в том, что обработчик net из коробки поддерживает подключение только по протоколу NFS версии 3. К счастью, поддержка 4-й версии добавляется очень просто.
Сначала установим пакет, в который входит нужный нам обработчик net, а также пакет утилит для работы с NFS (модуль nfsv4 и программа mount.nfs4):
pacman --root $root --dbpath $root/var/lib/pacman -S mkinitcpio-nfs-utils nfs-utils
Исправим обработчик net из папки hooks (вместо команды для монтирования nfsmount, теперь будем использовать mount.nfs4):
sed s/nfsmount/mount.nfs4/ "$root/usr/lib/initcpio/hooks/net" > "$root/etc/initcpio/hooks/net_nfs4"
С помощью установщика обработчика из папки install добавим модуль nfsv4 и программу mount.nfsv4 в iniramfs. Сначала копируем и переименовываем заготовку:
cp $root/usr/lib/initcpio/install/net $root/etc/initcpio/install/net_nfs4
Теперь исправляем только одну функцию build(), а всё остальное не трогаем:
nano $root/etc/initcpio/install/net_nfs4
build() {
add_checked_modules '/drivers/net/'
add_module nfsv4?
add_binary "/usr/lib/initcpio/ipconfig" "/bin/ipconfig"
add_binary "/usr/bin/mount.nfs4" "/bin/mount.nfs4"
add_runscript
}
Добавляем обработчик в initramfs путём исправления строки в файле mkinitcpio.conf:
nano $root/etc/mkinitcpio.conf
HOOKS="base udev net_nfs4"
[править] подготовка клиентского ядра и initrd
Необходимо подготовить ядро, под управлением
которого будут работать клиентские станции.
При конфигурировании клиентского ядра обязательно нужно включить:
- Поддержку сетевой карты
- Поддержку NFS
Ниже будет рассмотренно, как это осуществить
Для начала необходимо выяснить, какой модуль ответственнен за сетевую карту. На работающей машине сделайте:
cat /etc/modprobe.conf | grep eth
допустим, мы получили alias eth0 pcnet32.
После этого, нам необходимо выяснить, как она включается в ядро.
find /usr/src/linux/ | grep pcnet32
Так мы узнаем, в каком каталоге лежат файлы, ответственные за модуль.
Для драйверов сетевых карт это
/usr/src/linux/drivers/net
Осталось только узнать define-variable для модуля.
cat /usr/src/linux/drivers/net/Makefile | grep pcnet32
В выводе будет что-то похожее на CONFIG_PCNET32.
Далеко не у всех модулей имя define-variable совпадает с именем модуля.
Осталось только
cd /usr/src/linux make menuconfig
и, используя клавишу [/], ввести то, что после CONFIG_. Месторасположение нам укажут.
Можно, конечно, вручную поправить файл .config, но так можно нарушить зависимости.
Итак, сетевые карта включаются в Device Drivers -> Network Device Support -> Ethernet (10 or 100Mbit). Как ни странно, pcnet32 оказался AMD PCNet32 PCI support.
File Systems -> Netwok File Systems -> NFS file system support
- Поддержка функций dhcp ядром
Networking -> Network Options -> IP: kernel level avtoconfiguration
и соответствующие протоколы к нему (bootp и DHCP, хотя, возможно, будет достаточно только второго). Подразумевается, что TCP/IP-стек будет включён в ядро. Это очень важный момент. Без этой функции ядро сразу после загрузки высвободит выделенный айпи адрес и предоставить насройку пользователю (в initrd, например), а так же ядро будет игнорировать параметр ip=dhcp.
В этой ситуации поможет только явное указание адреса, что будет пригодно для загрузки только одной машины (или обязывает к немедленной смене адреса после загрузки).
IP-адрес можно указать так: ip=клиент:сервер:шлюз:маска:имя:устройство, но согласитесь, ip=dhcp лучше.
Кроме того, в File Systems -> Network File Systems появится не менее важный пункт:
Root file system on NFS
Заодно можно выставить оптимизацию под конкретный процессор и отключить неиспользуемые модули. Например IrDA, BlueTooth или IDE-через-LPT.
Initramfs
В этом примере мы будем забирать образ корневой фс с веб-сервера, расположенного на нашем сервере сетевой загрузки, то есть на 10.0.0.1. Решение было таким просто потому, что в нашем initramfs была утилита wget. Чтобы не тянуть большой объем данных по сети, мы решили сжать образ.
SquashfsSquashfs — это сжимающая файловая система, которая включена в ядро с версии 2.6.29. С ее помощью можно заархивировать каталог, примонтировать на loop устройство и читать с него, для записи же необходимо провести процедуру добавления файлов в архив. Так как при обращении к squashfs, вы читаете из архива, то это дает дополнительную нагрузку на cpu.
mksquashfs /mnt/rootfs/ rootfs.squashfs -noappend -always-use-fragments
du -hs rootfs.squashfs
92M rootfs.squashfs
Для более эфферктивного сжатия вы можете использовать опцию -comp, чтобы установить тип сжатия, по умолчанию используется gzip.
Далее надо научить init из initramfs забирать образ корня и помещать его в оперативную память.
init в initramfs — это скрипт на sh, который производит разбор опций из cmdline, монтирует фс, делает switch_root и запускает гланый init-процесс системы. Воспользуемся этим и допишем свои опции для cmdline. Напишем скрипт ram, который будет вызываться при значении опции boot=ram.
vim /usr/share/initramfs-tools/scripts/ram
#!/bin/bash
retry_nr=0
do_rammount()
{
log_begin_msg "Configuring networking"
configure_networking
log_end_msg
log_begin_msg "Downloading rootfs image"
mkdir -p /tmp/squashfs
wget ${rooturl} -O /tmp/squashfs/rootfs.squashfs
log_end_msg
log_begin_msg "Mounting rootfs image to /mnt/squashfs"
mkdir -p /mnt/squashfs
mount -t squashfs -o loop /tmp/squashfs/rootfs.squashfs /mnt/squashfs
log_end_msg
log_begin_msg "Mounting tmpfs and copy rootfs image"
mkdir -p ${rootmnt}
mount -t tmpfs -o size=1G none ${rootmnt}
cp -r -v /mnt/squashfs/* ${rootmnt} || exit 2
log_end_msg
log_begin_msg "Umount squashfs"
umount /mnt/squashfs || exit 2
log_end_msg
}
mountroot()
{
for x in $(cat /proc/cmdline); do
case $x in
rooturl=*)
export rooturl=${x#rooturl=}
;;
esac
done
log_begin_msg "Loading module squashfs"
modprobe squashfs
log_end_msg # For DHCP
modprobe af_packet
wait_for_udev 10
# Default delay is around 180s
delay=${ROOTDELAY:-180}
# loop until rammount succeeds
do_rammount
while [ ${retry_nr} -lt ${delay} ] && [ ! -e ${rootmnt}${init} ]; do
log_begin_msg "Retrying rammount"
/bin/sleep 1
do_rammount
retry_nr=$(( ${retry_nr} 1 ))
log_end_msg
done
}
Через параметр rooturl можно указывать откуда качать образ корневой фс. Для работы со squashfs необходимо подгрузить ее модуль в ядро. Указываем в /etc/initramfs-tools/initramfs.conf BOOT=ram и пересобираем initramfs
mkinitramfs -o /var/lib/tftpboot/initrd.img
Включаем машинку, на которой будем тестировать, и смотрим на происходящее. После успешной загрузки мы получили бездисковую систему, которая занимает в памяти около 300Мб, при этом мы может писать в нее, но после ребута, система вернется в свое первоначальное состояние.
В это примере, мы использовали squashfs просто для сжатия образа, но почему бы нам не попробовать примонтировать корневой раздел в squashfs и не посмотреть, что получится? Меняем наш скрипт, в функции do_rammount() оставляем только монтирование squashfs.
do_rammount()
{
log_begin_msg "Configuring networking"
configure_networking
log_end_msg
log_begin_msg "Downloading rootfs image"
mkdir -p /tmp/squashfs
wget ${rooturl} -O /tmp/squashfs/rootfs.squashfs
log_end_msg
log_begin_msg "Mounting rootfs image to /mnt/squashfs"
mkdir -p /mnt/squashfs
mount -t squashfs -o loop /tmp/squashfs/rootfs.squashfs ${rootmnt}
log_end_msg
}
Пересобираем initramfs, запускаем, смотрим. Система загружается в режиме ro, но зато занимает в памяти всего около 180Мб.В каких-то случаях монтирование в режиме ro это хорошо, но нас это не устраивает, но и просто так тратить оперативную память нам тоже не хочется. Выход же был найден при помощи Aufs.
AufsAufs позволяет делать каскадно-объединённое монтирование файловых систем — одну в режиме только на чтение, а вторую в rw. Работает она в режиме copy-on-write, то есть все изменения записываются на rw систему и после этого чтение производится с нее же. Опять переписываем наш скрипт. В фукнцию mountroot() добавляем
log_begin_msg "Loading module aufs"
modprobe aufs
log_end_msg
А фукнцию do_rammount() приводим к следующему виду:
do_rammount()
{
log_begin_msg "Configuring networking"
configure_networking
log_end_msg
log_begin_msg "Downloading rootfs image"
mkdir -p /tmp/squashfs
wget ${rooturl} -O /tmp/squashfs/rootfs.squashfs
log_end_msg
log_begin_msg "Mounting rootfs image to /mnt/ro"
mkdir -p /mnt/ro
mount -t squashfs -o loop /tmp/squashfs/rootfs.squashfs /mnt/ro
log_end_msg
log_begin_msg "Mounting tmpfs to /mnt/rw"
mkdir -p /mnt/rw
mount -t tmpfs -o size=1G none /mnt/rw
log_end_msg
log_begin_msg "Mounting aufs to /mnt/aufs"
mkdir -p /mnt/aufs
mount -t aufs -o dirs=/mnt/rw=rw:/mnt/ro=ro aufs /mnt/aufs
log_end_msg
[ -d /mnt/aufs/mnt/ro ] || mkdir -p /mnt/aufs/mnt/ro
[ -d /mnt/aufs/mnt/rw ] || mkdir -p /mnt/aufs/mnt/rw
mount --move /mnt/ro /mnt/aufs/mnt/ro #сдвигаем точку squashfs монтирования в aufs
mount --move /mnt/rw /mnt/aufs/mnt/rw #сдвигаем точку монтирования tmpfs в aufs
mount --move /mnt/aufs ${rootmnt} #сдвигаем точку монтирования aufs в ${rootmnt}
}
Пересобираем initramfs, запускаем, смотрим. Система занимает в памяти 181Мб, при этом мы можем менять ее, писать, читать. Все изменения хранятся отдельно в /mnt/rw, а сама система хранится в /mnt/ro.
В результате мы получили систему, которая грузится по сети, занимает небольшой объем в памяти, при этом после каждой перезагрузки пропадают все изменения (поэтому надо заранее собирать все нужные продукты жизнедеятельности системы в надежное место).