Table of Contents

Задача - запустить на хосте Proxmox виртуалку, которая загружалась бы по сети по NFS.
У виртуалки будет два интерфейса - один для выхода в сеть и один для взаимодействия с сервером NFS.

Настройка контейнера DHCP+NFS

На хосте Proxmox создаем профиль для запуска внутри контейнера сервера NFS.
В конфигурации контейнера два сетевых интерфейса. Один смотрит во внешнюю сеть, а второй - исключительно для загрузки виртуалки (на нем будут работать сервисы NFS и DHCP).
В данной конфигурации IP-адрес контейнера - 192.168.88.1. Этот интерфейс смотрит на виртуальную машину.
Запускаем это контейнер и в нем настраиваем:

sudo apt-get install isc-dhcp-server tftpd-hpa syslinux pxelinux nfs-kernel-server initramfs-tools

/etc/dhcp/dhcpd.conf

Настраиваем DHCP-зону в файлике /etc/dhcp/dhcpd.conf:

option domain-name "autosys.tk";
default-lease-time 600;
max-lease-time 7200;

allow booting;
allow bootp;

subnet 192.168.88.0 netmask 255.255.255.0 {
  range 192.168.88.100 192.168.88.254;
  option broadcast-address 192.168.88.255;
  filename "/pxelinux.0";
}

host pxe_client {
  hardware ethernet 76:4B:48:28:D3:A4;
  fixed-address 192.168.88.100;
}

Добавлять статичный адрес необходимо для того, чтобы у адаптера всегда был один IP-адрес. В противном случае - адаптер будет иметь два IP-адреса. Два адреса адаптер получает даже если интерфейс не сконфигурирован в netplan.

/etc/default/isc-dhcp-server

Указываем, что наш DHCP-сервер должен работать только на интерфейсе, который не смотри во внешнюю сеть:

INTERFACESv4="eth1"

перезагружаем контейнер и смотрим, что все норм:

service nfs-server status
service isc-dhcp-server status

/etc/default/tftpd-hpa

Настраиваем tftp-сервер:

# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/var/lib/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure"

Копируем нужные файлы:

cp /usr/lib/PXELINUX/pxelinux.0 /var/lib/tftpboot/
cp /var/lib/tftpboot/boot/isolinux/menu.c32 /var/lib/tftpboot/
mkdir -p /var/lib/tftpboot/boot
cp -r /usr/lib/syslinux/modules/bios /var/lib/tftpboot/boot/isolinux
mkdir /var/lib/tftpboot/pxelinux.cfg

Настраиваем сервер NFS

Создаем папку, в которой будет размещаться корневая директория нашей бездисковой виртуалки:

mkdir /nfsroot

/etc/exports

Прописываем экспорт этой директории в файлике /etc/exports:

/nfsroot             192.168.88.0/24(rw,no_root_squash,async,insecure)

и применяем изменения

exportfs -rv

Готовим систему, которая будет грузиться с NFS-шары

Делаем обычную виртуальную машину и устанавливаем в ней нужный нам дистрибутив Linux. В моем случае это будет Ubuntu-18.04 Server + KDE.
Для начала я установлю только голый Ubuntu-18.04 Server и сделаю его бездисковым. После установки, внутри виртуалки выполняем:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get -y purge cloud-init && sudo rm -rf /etc/cloud
sudo apt-get -y install nfs-common

Настраиваем и пересобираем initrd:

sudo cp /boot/vmlinuz-`uname -r` ~/
sudo sed -i 's/MODULES=.*$/MODULES=netboot/g' /etc/initramfs-tools/initramfs.conf
echo 'virtio_net' >> /etc/initramfs-tools/modules
sudo mkinitramfs -o ~/initrd.img-`uname -r`  

Копируем систему на NFS-сервер:

sudo mount -t nfs -o nolock 192.168.88.1:/nfsroot /mnt
sudo cp -ax /. /mnt/.
sudo cp -ax /dev/. /mnt/dev/.
sudo cp -ax /boot/. /mnt/boot/.
sudo umount /mnt

Для быстрой загрузки хорошо бы, чтобы первым интерфейсом был тот, с которого будет грузиться система.

Настраиваем параметры загрузки по сети

Возвращаемся в контейнер, который у нас NFS-сервер и копируем ядро системы и initrd в папку tftp:

sudo cp /nfsroot/boot/vmlinuz-4.15.0-45-generic /var/lib/tftpboot/
sudo cp /nfsroot/boot/initrd.img-4.15.0-45-generic /var/lib/tftpboot/

В вашей системе версии наверное будут другие.

/var/lib/tftpboot/pxelinux.cfg/default

Создаем конфигурацию PXE. Тут пишем актуальные имена файлов (ядра и initrd), а также путь до корневой директории на NFS-сервере:

DEFAULT menu.c32
prompt 0
timeout 5

LABEL Ubuntu Linux 18.04
        menu default
        menu label Ubuntu Linux 18.04
        KERNEL vmlinuz-4.15.0-45-generic
        APPEND root=/dev/nfs initrd=initrd.img-4.15.0-45-generic nfsroot=192.168.88.1:/nfsroot ip=dhcp rw

даем права на чтение папки /var/lib/tftpboot:

chmod -R 777 /var/lib/tftpboot

Рестартуем сервис tftpd-hpa:

service tftpd-hpa restart

Финальные штрихи

В контейнере NFS-сервере в папке со скопированной системой поправляем /etc/fstab :

nano /nfsroot/etc/fstab

Указываем, что в качестве корня нужно монтировать /dev/nfs и отключаем swap:

/dev/nfs / ext4 defaults 0 0
#/swap.img      none    swap    sw      0       0

Также нужно прописать сетевому интерфейсу, который используется для загрузки тип static. Иначе система будет тупить при загрузке, пытаясь повторно сконфигурировать этот интерфейс.
Файлик /nfsroot/etc/netplan/50-cloud-init.yaml приводим к такому виду:

network:
    ethernets:
        ens18:
            addresses: []
            dhcp4: no
        ens19:
            addresses: [192.168.x.x/24]
            gateway4: 192.168.x.x
            nameservers:
              search: [domain.name]
              addresses: [192.168.x.x,192.168.x.x]
            dhcp4: no
            dhcp6: no
    version: 2

Тут первый интерфейс ens18, для доступа к корневой файловой системе имеет тип static без адреса, а для выхода в сеть используется второй интерфейс ens19, который получает статический адрес.

Пробуем загрузиться

Выключаем виртуалку. Отсоединяаем от нее диск и выставляем загрузку по сети.