letBulochkin.github.io

Установка CentOS по сети: основные принципы

2023-02-20

Зачем это нужно

В расширяющихся серверных кластерах для ускорения процесса ввода новых хостов зачастую применяют установку операционной системы по сети. Такой способ также позволяет использовать централизованный сервер установки ОС для хранения и управления их загрузочными конфигурациями. Ниже я постараюсь кратко описать основные принципы, по которым работает установка ОС по сети.

PXE Boot

За установку ОС по сети со стороны клиента отвечает PXE, или PreBoot eXecution Environment – среда, обеспечивающая загрузку компьютера без использования локального носителя. Для обеспечения загрузки по PXE используются протоколы DHCP и TFTP, а PXE-код реализован в большинстве современных сетевых карт.

Загрузка по PXE в общем виде состоит из следующих этапов:

  1. PXE-программа клиента отправляет широковещательный DHCPDISCOVER-пакет с PXE-атрибутами на порт 67.
  2. DHCP-сервер в ответ отправляет сетевую конфигурацию клиента (IP-адрес, маску, т.д.) и IP-адрес TFTP-сервера.
  3. Клиент обращается по полученному адресу и загружает через TFTP в память минимальный набор для начала загрузки ОС. Для Linux это загрузчик (бутлоадер), ядро и initrd/initramfs.

DHCP-сервер должен быть настроен соответствующим образом, чтобы распознать запрос от PXE-клиента. Например, в dnsmasq для этого существует опция dhcp-boot:

$ man dnsmasq
...
-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
...
$ cat /etc/dnsmasq.conf
...
dhcp-boot=tag:normalarch,/var/images/pxelinux.0
dhcp-boot=/var/images/pxelinux.0,cobbler-server,192.168.1.17

dnsmasq сам может выступать в роли TFTP-сервера (для этого в конфиге должна быть активирована опция enable-tftp). В таком случае после получения запроса от клиента dnsmasq отправит бутлоадер, путь к которому является обязательным значением опции dhcp-boot, в примере выше это /var/images/pxelinux.0. Если кроме пути к бутлоадеру также указан адрес и/или хостнейм стороннего TFTP-сервера, то в ответ клиент получит именно их. В примере выше указано, что TFTP-сервер живёт по адресу 192.168.1.17 и имеет хостнейм cobbler-host. dnsmasq также позволяет варьировать значения dhcp-boot в зависимости от значений переданных в запросе DHCP-опций (tag:normalarch). Для этого см. dhcp-match в доках dnsmasq.

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

В качестве примера предположим, что DHCP-сервер имеет адрес 192.168.1.16, TFTP-сервер - 192.168.1.17, а клиенту будет назначен адрес 192.168.1.101. Сняв дамп сетевого трафика на DHCP-сервере во время PXE-загрузки хоста, можно увидеть, как приходит DHCP-запрос от клиента, не подключённого к сети (IP-адрес 0.0.0.0). В ответ посылается широковещательный пакет с адресом TFTP-сервера:

$ tcpdump -nnpi any port 67 or port 68 or port 69
...
23:29:18.603274 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from aa:bb:cc:dd:ee:ff, length 300
23:29:18.603274 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from aa:bb:cc:dd:ee:ff, length 300
23:29:18.604143 IP 192.168.1.16.67 > 255.255.255.255.68: BOOTP/DHCP, Reply, length 340
23:29:18.604152 IP 192.168.1.16.67 > 255.255.255.255.68: BOOTP/DHCP, Reply, length 340

Вскоре на TFTP-сервере начнётся отправка данных клиенту. Так как TFTP основан на UDP, то в дампе трафика фигурирует этот протокол. Передача начинается с отправки запроса на чтение (read request, RRQ):

$ tcpdump -nnpi any host 192.168.1.101
...
23:29:43.509633 IP 192.168.1.101.49155 > 192.168.1.17.69:  149 RRQ "/images/diskless/initramfs.gz" octet tsize 0 blksize 1408
23:29:43.720371 IP 192.168.1.101.49155 > 192.168.1.17.38292: UDP, length 4
23:29:43.720371 IP 192.168.1.101.49155 > 192.168.1.17.38292: UDP, length 4
23:29:43.720383 IP 192.168.1.17.38292 > 192.168.1.101.49155: UDP, length 1412
23:29:43.720385 IP 192.168.1.17.38292 > 192.168.1.101.49155: UDP, length 1412

Процесс установки на примере CentOS

После загрузки с TFTP-сервера бутлоадер PXELINUX помещает ядро в память и распаковывает initrd/initramfs (о том, что это – ниже). Ядро системы выполняет необходимые задачи, в том числе связанные с памятью и аппаратной частью сервера, и затем передаёт управление init-процессу. init выполняет задачи на прикладном уровне, например монтирует файловые системы.

На иллюстрации выше: стандартная схема загрузки CentOS. В нашем случае вместо загрузчика GRUB2 используется PXELINUX.

initrd (Initial RAM Disk) призван решить множество проблем и узких мест в связке kernel - init. Например, для монтирования корневой файловой системы в отдельных случаях init могут понадобиться специальные модули и драйверы, вшивать которые в образ ядра нецелесообразно. Или, например, если каталог /usr монтируется в отдельной файловой системе, программы и драйверы, читающие и записывающие файлы в /usr не могут быть использованы, пока каталог не будет примонтирован. А если для монтирования /usr нужны программы и драйверы, зависящие от /usr, то круг замкнётся и система не загрузится.

initrd - это образ корневой файловой системы, который распаковывается ядром как блочное устройство в память перед монтированием настоящей корневой ФС. initrd содержит в себе необходимые инструменты для подготовки файловых систем прежде чем управление будет передано init. Ядро вызывает установочный скрипт, обычно называемый linuxrc, который выполняет необходимые действия, а затем вызывает init на реальной корневой ФС.

У initrd есть ряд недостатков, которые решает initramfs. initrd - полноценное блочное устройство, имеющее фиксированный размер и требующее собственную файловую систему (драйвер которой, к тому же, должен быть зашит в ядро). initramfs использует преимущества упрощённой файловой системы tmpfs, которая позволяет размещать файлы в памяти непосредственно. initramfs представляет собой, по сути, архив файлов, который распаковывается в память, что значительно проще операций с блочным устройством.

Для бездисковых систем initramfs может стать основной корневой файловой системой. В состав архива можно включить bootstrap-скрипт, который автоматически запустится и настроит CentOS после загрузки. Для обычных систем установку CentOS может упростить использование kickstart-конфигов для встроенного установщика Anaconda. В kickstart-конфиге можно прописать большое количество опций, например, указать, на какой именно диск устанавливать систему; разбирать синтаксис kickstart в этом посте я не буду. Бутлоадеру необходимо указать на использование kickstart-конфига, прописав путь к нему.

Например, конфигурации PXELINUX хранятся на TFTP-сервере, в том числе и в Cobbler, в каталоге /var/lib/tftpboot/pxelinux.cfg. В файле default этого каталога можно увидеть следующее:

LABEL EL7
        kernel /images/centos-7.2-x86_64/vmlinuz
        MENU LABEL EL7
        append initrd=/images/centos-7.2-x86_64/initrd.img ksdevice=bootif kssendmac text  ks=http://192.168.1.17/cblr/svc/op/ks/profile/EL7
        ipappend 2

Параметр ks= как раз указывает на путь к kickstart-конфигу, который будет загружен и исполнен при установке CentOS 7.

Материалы для чтения: