Как я понимаю, прелесть данного метода в том, что с сервера снимаеются накладные расходы на обслуживание файловой системы, т.к. клиент работает с блочным устройством и её обслуживание осуществляется полностью самим клиентом.
В реализации данного метода загрузки будут задействованы следующие службы:
DHCP-сервер, который должен передавать клиенту данные о адресе TFTP-сервера и имени файла с которого нужно начать загрузку системы
TFTP-сервер, с которого производится чтение базовой системы управляющей загрузкой
Модуль загрузчика iPXE, который осуществляет подключение iSCSI-диска и инициализирует с него загрузку
Сервер сетевого хранилища, содержащий блочные устройства, доступ к которым выдается по средствам протокола iSCSI
Следует сразу оговориться, что данная статья орентирована на системы, которые поддерживают Legacy-режим (или CSM) загруки через стандартный PXE протокол. Не все современные BIOS-ы в десктопных системах поддерживают данный режим.
1 Настройка DHCP-сервера
Настройка DHCP-сервера сводится к добавлению параметра, передающего клиенту данные о расположении TFTP-сервера и файла с которого нужно начать загрузку. Для различных маршрутизаторов это будет по разному, но суть везде одна: передать IP-адрес next-server - адрес TFTP сервера и имя файла для загрузки, в нашем случае - pxelinux.0.
2 Настройка TFTP-сервера
В Ubuntu 20.04 нам понадобится установить следующие пакеты:
Если нужно чтобы разные машины в сети получали собственную конфигурацию для загрузки, то необходимо для каждой создать свой конфигурационный файл. Файл должен находиться в папке /srv/tftp/pxelinux.cfg/ и иметь формат: 01-88-99-aa-bb-cc-dd, где 01 - это префикс, а 88-99-aa-bb-cc-dd - это mac-адрес клиента.
Создаем файл конфигурации модуля ipxe.lkrn, для подключения iSCSI диска и передачи эстафеты загруки с этого диска:
Естественно, что в последней строке данного файла, адрес 192.168.0.10 и имя iSCSI-таргета iqn.2005-10.org.freenas.ctl:boot1 могут быть другими.
3 Настройка сетевого хранилища и создание iSCSI таргета
Для простоты администрирования я использую для этих целей TrueNAS CORE. Процесс установки самого TrueNAS описывать не буду, опишу только шаги по настройке самого таргета.
Для начала, в разделе “Storage” необходимо создать пул, внутри которого уже будут создаваться тома (volume) дисков экспортируемых через iSCSI-таргеты. В конечном итоге это будет выглядеть примерно так:
После чего, в разделе “Services”, необходимо включить сервис iSCSI. Выглядит это примерно так:
Далее, в разделе “Sharing ➔ Block Shares (iSCSI)”, нам нужно создать таргет для загрузки. Проще всего это сделать в режиме Wizard-а, где необходимо выполнить чертыре шага:
В данном примере важные параметры выделены красным подчеркиванием. Прмер подразумевает самый не безопасный режим экспорта блочного устройчтва, в нем отсутствуют какие либо проверки имени инициатора, имени пользователя, пароля, принадлежности к какой-либо подсети и т.д., но для начала думаю этого хватит, т.к. в последствии это всё можно донастроить при необходимости.
3.1 Подключение/отключение iSCSI диска к системе с которой будет произодиться установка конечной системы
Чтобы работать с iSCSI в системе должен быть установлен пакет open-iscsi:
1
sudo apt-get install -y open-iscsi
Для того чтобы получить список доступных iSCSI-таргетов, выполняем:
1
sudo iscsiadm -m discovery -t st -p 192.168.0.10
В результате мы должны получить примерно такой вывод:
4 Создание загрузочного образа / установка системы
Мною было прочитано энное колличество туториалов по организации загрузки с iSCSI диска, и в результате экспериментов по настройке данной функии, в какой-то момент, я устал от повторяющихся действий, где так же, плюс ко всему, можно допустить ошибку, совершая множество действий. В результате я написал bash-скрипт, который выполняет все эти действия автоматически. Скрипт может генерировать образ загрузочного диска заданного размера, либо производить установку прямо на блчное устройство. В начале скрипта, в виде переменных, перечислены основные параметры. Сам скрипт выглядит так:
#!/bin/bash
IMAGE_SIZE=10# Image size in gigabytesMAKE_IMAGE=true# Installation mode: image / block deviceTARGET_DEVICE=boot1.img # Target device or image file#TARGET_DEVICE=/dev/sdcBOOT_DISK_SIZE=500M # Boot partition sizeAPT_SOURCE='https://mirror.yandex.ru/ubuntu/'# Bootstrap installation packages sourceCODENAME='jammy'# Distribution codenameUSERNAME='superadmin'# System administrator user name (sudo user)PASSWORD='MegaUltraPa$$word!'# System administrator user passwordHOSTNAME='pxe-boot-01'# System host nameETH_IF='enp3s0'# Device for make it unmanaged by Network ManagerISCSI_INITIATOR='iqn.2005-10.org.freenas.ctl:client1'# iSCSI initiator nameISCSI_TARGET_NAME='iqn.2005-10.org.freenas.ctl:boot1'# iSCSI target nameISCSI_TARGET_IP='192.168.0.10'# iSCSI target IPif[$(whoami) !='root'];thenecho"You must be root user!";exit 0;fiif[$MAKE_IMAGE==true];thenif[ ! -f $TARGET_DEVICE];thenecho"Make image file..." dd if=/dev/zero of=${TARGET_DEVICE}bs=1M count=$((IMAGE_SIZE *1024))conv=fdatasync status=progress
ERROR=$?;if[$ERROR -ne 0];thenecho"Error creation if image file!";exit$ERROR;fielseecho"Image file exists!"exit0fifiecho"Create disk partitions..."echo -e ",${BOOT_DISK_SIZE},L,*\n,+,L\n"| sfdisk -X dos ${TARGET_DEVICE}ERROR=$?;if[$ERROR -ne 0];thenecho"Error creating disk partitions!";exit$ERROR;fimkdir -p /mnt/bootstrap
if[$MAKE_IMAGE==true];thenecho"Create filesystem on image partitions..."LOOP_DEVICE=$(losetup -f ${TARGET_DEVICE} -P --show) mkfs.ext4 ${LOOP_DEVICE}p1
mkfs.ext4 ${LOOP_DEVICE}p2
mount ${LOOP_DEVICE}p2 /mnt/bootstrap
mkdir -p /mnt/bootstrap/boot
mount ${LOOP_DEVICE}p1 /mnt/bootstrap/boot
elseecho"Create filesystem on target device partitions..." mkfs.ext4 -F ${TARGET_DEVICE}1 mkfs.ext4 -F ${TARGET_DEVICE}2 mount ${TARGET_DEVICE}2 /mnt/bootstrap
mkdir -p /mnt/bootstrap/boot
mount ${TARGET_DEVICE}1 /mnt/bootstrap/boot
fiERROR=$?;if[$ERROR -ne 0];thenecho"Error creating filesystems!";exit$ERROR;firm -rf /mnt/bootstrap/lost+found
rm -rf /mnt/bootstrap/boot/lost+found
debootstrap --include=linux-image-generic,openssh-server,language-pack-ru,apt,sudo,nano,vim,bash-completion,wget,curl,open-iscsi,initramfs-tools,grub2-common,grub-pc ${CODENAME} /mnt/bootstrap ${APT_SOURCE}ERROR=$?;if[$ERROR -ne 0];thenecho"Error bootstrap system!";exit$ERROR;fiecho"Mount system devices to target for chroot..."mount --bind /proc /mnt/bootstrap/proc
mount --bind /sys /mnt/bootstrap/sys
mount --bind /dev /mnt/bootstrap/dev
mount --bind /run /mnt/bootstrap/run
echo"Make target system modifications..."chrun (){ chroot /mnt/bootstrap bash -c "$1";}echo"Update target hostname..."echo"${HOSTNAME}" > /mnt/bootstrap/etc/hostname
echo"Configure iSCSI options..."echo"iscsi" >> /mnt/bootstrap/etc/initramfs-tools/modules
echo"InitiatorName=${ISCSI_INITIATOR}" > /mnt/bootstrap/etc/iscsi/initiatorname.iscsi
touch /mnt/bootstrap/etc/iscsi/iscsi.initramfs
sed -i 's#^\(GRUB_CMDLINE_LINUX_DEFAULT="quiet splash\)"$#\1 ip=dhcp ISCSI_INITIATOR='${ISCSI_INITIATOR}' ISCSI_TARGET_NAME='${ISCSI_TARGET_NAME}' ISCSI_TARGET_IP='${ISCSI_TARGET_IP}' ISCSI_TARGET_PORT=3260"#' /mnt/bootstrap/etc/default/grub
echo"Configure target network..."cat > /mnt/bootstrap/etc/netplan/10-iscsi-interface.yaml << EOF
network:
ethernets:
${ETH_IF}:
dhcp4: false
dhcp6: false
version: 2
EOFif[$MAKE_IMAGE==true];thenBOOT_UUID=$(blkid -s UUID -o value ${LOOP_DEVICE}p1)DATA_UUID=$(blkid -s UUID -o value ${LOOP_DEVICE}p2)elseBOOT_UUID=$(blkid -s UUID -o value ${TARGET_DEVICE}1)DATA_UUID=$(blkid -s UUID -o value ${TARGET_DEVICE}2)fiecho"Update /etc/fstab file..."cat > /mnt/bootstrap/etc/fstab << EOF
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# systemd generates mount units based on this file, see systemd.mount(5).
# Please run 'systemctl daemon-reload' after making changes here.
#
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=${DATA_UUID} / ext4 errors=remount-ro 0 1
UUID=${BOOT_UUID} /boot ext4 defaults 0 2
EOFecho"Update APT sources..."cat > /mnt/bootstrap/etc/apt/sources.list << EOF
deb $APT_SOURCE $CODENAME main restricted
deb $APT_SOURCE $CODENAME universe
deb $APT_SOURCE $CODENAME multiverse
#deb $APT_SOURCE $CODENAME partner
deb $APT_SOURCE $CODENAME-security main restricted
deb $APT_SOURCE $CODENAME-security universe
deb $APT_SOURCE $CODENAME-security multiverse
EOFchrun "apt-get update"echo"Make administrator user..."chrun "useradd ${USERNAME} -m -s /bin/bash"chrun "echo \"${USERNAME}:${PASSWORD}\" | chpasswd"chrun "usermod -aG sudo ${USERNAME}"echo"Install GRUB to target system..."if[$MAKE_IMAGE==true];then chrun "grub-install ${LOOP_DEVICE}"else chrun "grub-install ${TARGET_DEVICE}"fichrun "update-grub"echo"Update intiramfs..."chrun "update-initramfs -u"echo"Unmount all mounted resources..."umount /mnt/bootstrap/proc
umount /mnt/bootstrap/dev
umount /mnt/bootstrap/sys
umount /mnt/bootstrap/run
umount /mnt/bootstrap/boot
umount /mnt/bootstrap
if[$MAKE_IMAGE==true];then losetup -d ${LOOP_DEVICE};fi
Если приведенный выше скрипт был запущен в режиме создания файла-образа, то перенести его на результирующий диск можно с помощью приведенной ниже команды:
После выполнения всех операций по установке системы следует, на всякий случай, выполнить комманду sync и отключить iSCSI-устройство.
Если всё получилось, то теперь можно пробовать загрузиться в новоиспеченную систему и размышлять над тем как это всё модифицировать под собственные нужды.
Еще, в качестве бонуса, приведу модифицированную версию скрипта установки, целью которого была установка Linux Mint 21 (Vanessa). Для его использования необходимо обратить внимание на то что он копирует GPG-ключ от репозитория Linux Mint в результирующую систему, который нужно сначала где-то взять. Мне это было легко, т.к. я под ней и работаю и у меня этот ключ есть на локальном диске. Вы можете извлечь его из офицального образа и расположить в папке resources рядом со скриптом.