PXE + Kickstart: как мы автоматизировали установку Linux на 50 серверах для хостинга «РуДата»

Ситуация: 50 серверов и один инженер с флешкой

Хостинг-провайдер «РуДата» обратился к нам в itfresh.ru с задачей: закупили партию из 50 серверов Dell PowerEdge R650, нужно установить Rocky Linux 9 на все. Текущий процесс — инженер приходит к каждому серверу с USB-флешкой, вручную проходит установщик Anaconda, вбивает параметры разбивки, сети, пакетов. На один сервер уходит 40-60 минут, на 50 — три рабочие недели.

Дополнительные требования:

  • Разные конфигурации — 30 серверов под KVM-виртуализацию, 10 под Ceph-хранилище, 10 под bare-metal аренду
  • Стандартизация — одинаковая базовая конфигурация: NTP, DNS, SSH hardening, мониторинг-агент
  • Скорость — новый сервер должен быть готов за 15-20 минут без участия инженера
  • Поддержка UEFI — новые серверы загружаются только в UEFI-режиме

Решение: развернуть инфраструктуру PXE-загрузки с Kickstart для автоматической установки.

Архитектура PXE-загрузки: DHCP + TFTP + HTTP

PXE (Preboot eXecution Environment) позволяет серверу загрузиться по сети без локальных носителей. Процесс:

  1. Сервер включается и отправляет DHCP Discover с опцией PXE
  2. DHCP-сервер выдаёт IP-адрес + адрес TFTP-сервера + имя загрузчика
  3. Сервер скачивает загрузчик (pxelinux.0 или grubx64.efi) по TFTP
  4. Загрузчик скачивает конфигурацию меню, ядро и initrd
  5. Ядро запускает установщик, который загружает Kickstart-файл по HTTP
  6. Установка проходит полностью автоматически

Нам потребовалось три сервиса на одном сервере (pxe-server, 10.10.1.10):

# Установка необходимых пакетов на Rocky Linux 9
sudo dnf install -y dhcp-server tftp-server httpd syslinux-tftpboot \
  grub2-efi-x64 shim-x64

# Создание структуры каталогов
sudo mkdir -p /var/lib/tftpboot/{pxelinux.cfg,uefi,images/rocky9}
sudo mkdir -p /var/www/html/{kickstart,iso,repos}

# Скачиваем Rocky Linux 9 ISO и монтируем
wget https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9.3-x86_64-dvd.iso \
  -O /var/www/html/iso/Rocky-9.3-x86_64-dvd.iso
sudo mount -o loop /var/www/html/iso/Rocky-9.3-x86_64-dvd.iso /var/www/html/repos/rocky9

# Копируем ядро и initrd для PXE
sudo cp /var/www/html/repos/rocky9/images/pxeboot/vmlinuz \
  /var/lib/tftpboot/images/rocky9/
sudo cp /var/www/html/repos/rocky9/images/pxeboot/initrd.img \
  /var/lib/tftpboot/images/rocky9/

DHCP-сервер с PXE-опциями

DHCP-сервер должен отдавать не только IP-адрес, но и два PXE-специфичных параметра: адрес TFTP-сервера (next-server) и имя файла загрузчика (filename). Важно: для UEFI и Legacy BIOS файлы загрузчика разные.

# /etc/dhcp/dhcpd.conf
authoritative;
default-lease-time 600;
max-lease-time 7200;

# Опция для определения архитектуры клиента
option architecture-type code 93 = unsigned integer 16;

subnet 10.10.1.0 netmask 255.255.255.0 {
    range 10.10.1.100 10.10.1.200;  # диапазон для PXE-клиентов
    option routers 10.10.1.1;
    option domain-name-servers 10.10.1.10, 8.8.8.8;
    option domain-name "rudata.internal";
    next-server 10.10.1.10;  # TFTP-сервер

    # Выбор загрузчика в зависимости от типа прошивки
    if option architecture-type = 00:07 {
        # UEFI x86_64
        filename "uefi/grubx64.efi";
    } elsif option architecture-type = 00:09 {
        # UEFI x86_64 (alternative)
        filename "uefi/grubx64.efi";
    } else {
        # Legacy BIOS
        filename "pxelinux.0";
    }
}

# Фиксированные адреса для конкретных серверов (по MAC)
host srv-kvm-01 {
    hardware ethernet aa:bb:cc:dd:ee:01;
    fixed-address 10.10.1.101;
    option host-name "srv-kvm-01";
}
host srv-kvm-02 {
    hardware ethernet aa:bb:cc:dd:ee:02;
    fixed-address 10.10.1.102;
    option host-name "srv-kvm-02";
}
# Запуск и включение DHCP-сервера
sudo systemctl enable --now dhcpd

# Проверка синтаксиса конфигурации
sudo dhcpd -t -cf /etc/dhcp/dhcpd.conf

# TFTP-сервер
sudo systemctl enable --now tftp.socket

# Firewall
sudo firewall-cmd --permanent --add-service={dhcp,tftp,http}
sudo firewall-cmd --reload

Альтернатива ISC DHCP — dnsmasq, который проще в настройке для небольших сетей:

# /etc/dnsmasq.conf — альтернативный вариант
interface=eth0
dhcp-range=10.10.1.100,10.10.1.200,255.255.255.0,1h
dhcp-option=3,10.10.1.1     # gateway
dhcp-option=6,10.10.1.10    # DNS

# PXE boot с автоопределением BIOS/UEFI
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-match=set:efi-x86_64,option:client-arch,9
dhcp-match=set:bios,option:client-arch,0

dhcp-boot=tag:efi-x86_64,uefi/grubx64.efi
dhcp-boot=tag:bios,pxelinux.0

enable-tftp
tftp-root=/var/lib/tftpboot

GRUB2 для UEFI и pxelinux для Legacy BIOS

Для UEFI-серверов (все новые Dell PowerEdge) нужен GRUB2. Для совместимости со старым оборудованием сохраняем и pxelinux.

GRUB2 (UEFI):

# Копируем EFI-загрузчики
sudo cp /boot/efi/EFI/rocky/grubx64.efi /var/lib/tftpboot/uefi/
sudo cp /boot/efi/EFI/rocky/shimx64.efi /var/lib/tftpboot/uefi/

# /var/lib/tftpboot/uefi/grub.cfg — меню GRUB2 для PXE
set timeout=10
set default=0

menuentry 'Rocky Linux 9 — KVM Host (auto)' --id kvm {
    linuxefi images/rocky9/vmlinuz \
        inst.repo=http://10.10.1.10/repos/rocky9 \
        inst.ks=http://10.10.1.10/kickstart/ks-kvm.cfg \
        ip=dhcp \
        net.ifnames=0 biosdevname=0 \
        console=tty0 console=ttyS1,115200n8
    initrdefi images/rocky9/initrd.img
}

menuentry 'Rocky Linux 9 — Ceph OSD (auto)' --id ceph {
    linuxefi images/rocky9/vmlinuz \
        inst.repo=http://10.10.1.10/repos/rocky9 \
        inst.ks=http://10.10.1.10/kickstart/ks-ceph.cfg \
        ip=dhcp \
        net.ifnames=0 biosdevname=0
    initrdefi images/rocky9/initrd.img
}

menuentry 'Rocky Linux 9 — Bare Metal (auto)' --id bare {
    linuxefi images/rocky9/vmlinuz \
        inst.repo=http://10.10.1.10/repos/rocky9 \
        inst.ks=http://10.10.1.10/kickstart/ks-bare.cfg \
        ip=dhcp
    initrdefi images/rocky9/initrd.img
}

menuentry 'Boot from local disk' --id local {
    exit
}

pxelinux (Legacy BIOS):

# Копируем файлы syslinux
sudo cp /usr/share/syslinux/{pxelinux.0,menu.c32,ldlinux.c32,libutil.c32} \
  /var/lib/tftpboot/

# /var/lib/tftpboot/pxelinux.cfg/default
DEFAULT menu.c32
PROMPT 0
TIMEOUT 100
MENU TITLE RuData PXE Boot Menu

LABEL kvm
    MENU LABEL Rocky Linux 9 - KVM Host (auto)
    KERNEL images/rocky9/vmlinuz
    APPEND initrd=images/rocky9/initrd.img inst.repo=http://10.10.1.10/repos/rocky9 inst.ks=http://10.10.1.10/kickstart/ks-kvm.cfg ip=dhcp

LABEL ceph
    MENU LABEL Rocky Linux 9 - Ceph OSD (auto)
    KERNEL images/rocky9/vmlinuz
    APPEND initrd=images/rocky9/initrd.img inst.repo=http://10.10.1.10/repos/rocky9 inst.ks=http://10.10.1.10/kickstart/ks-ceph.cfg ip=dhcp

LABEL local
    MENU LABEL Boot from local disk
    LOCALBOOT 0

Kickstart-файлы: полная автоматизация установки

Kickstart — формат файлов для автоматической установки RHEL-семейства (Rocky, Alma, CentOS, Fedora). Описывает всё: разбивку диска, пакеты, сеть, пользователей, пост-установочные скрипты.

Наш Kickstart для KVM-хостов:

# /var/www/html/kickstart/ks-kvm.cfg
# Rocky Linux 9 — KVM Hypervisor Host

# Системные настройки
text                          # текстовый режим (без GUI)
lang ru_RU.UTF-8
keyboard us
timezone Europe/Moscow --utc --ntpservers=ntp.rudata.internal
rootpw --iscrypted $6$rounds=100000$salt$hashedpasswordhere
firewall --enabled --ssh
selinux --enforcing
auth --enableshadow --passalgo=sha512

# Сеть — bond из двух интерфейсов
network --bootproto=dhcp --device=eth0 --activate --onboot=yes
network --hostname=localhost.localdomain  # hostname задаётся в %post

# Загрузчик
bootloader --location=mbr --driveorder=sda --append="crashkernel=auto"

# Разбивка диска (2x 480GB SSD в RAID1 для системы)
zerombr
clearpart --all --initlabel --drives=sda,sdb
part raid.1 --size=1024 --ondisk=sda --asprimary
part raid.2 --size=1024 --ondisk=sdb --asprimary
part raid.3 --size=51200 --ondisk=sda
part raid.4 --size=51200 --ondisk=sdb
part raid.5 --size=1 --grow --ondisk=sda
part raid.6 --size=1 --grow --ondisk=sdb

raid /boot --level=1 --device=md0 --fstype=ext4 raid.1 raid.2
raid pv.01 --level=1 --device=md1 raid.3 raid.4
raid pv.02 --level=1 --device=md2 raid.5 raid.6

volgroup vg_system pv.01
volgroup vg_libvirt pv.02

logvol / --vgname=vg_system --name=lv_root --size=20480 --fstype=xfs
logvol /var --vgname=vg_system --name=lv_var --size=10240 --fstype=xfs
logvol /var/log --vgname=vg_system --name=lv_log --size=10240 --fstype=xfs
logvol swap --vgname=vg_system --name=lv_swap --size=8192
logvol /var/lib/libvirt --vgname=vg_libvirt --name=lv_libvirt --size=1 --grow --fstype=xfs

# Пакеты
%packages
@^minimal-environment
qemu-kvm
libvirt
virt-install
virt-manager
bridge-utils
open-vm-tools
nano
wget
curl
net-tools
bind-utils
tcpdump
chrony
zabbix-agent2
python3
%end

# Пост-установочный скрипт
%post --log=/root/ks-post.log
#!/bin/bash
set -ex

# SSH hardening
sed -i 's/^#PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
mkdir -p /root/.ssh
curl -s http://10.10.1.10/kickstart/authorized_keys > /root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys

# Настройка hostname по IP (последний октет)
IP=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
OCTET=$(echo $IP | cut -d. -f4)
HOSTNAME="srv-kvm-$(printf '%02d' $OCTET)"
hostnamectl set-hostname $HOSTNAME

# NTP
sed -i 's/^pool .*/server ntp.rudata.internal iburst/' /etc/chrony.conf
systemctl enable chronyd

# Включение libvirtd
systemctl enable libvirtd

# Настройка bridge для виртуальных машин
nmcli connection add type bridge con-name br0 ifname br0 ipv4.method manual \
  ipv4.addresses $IP/24 ipv4.gateway 10.10.1.1 ipv4.dns 10.10.1.10
nmcli connection add type bridge-slave con-name br0-port1 ifname eth0 master br0

# Zabbix agent
sed -i "s/^Server=.*/Server=10.10.1.50/" /etc/zabbix/zabbix_agent2.conf
sed -i "s/^Hostname=.*/Hostname=$HOSTNAME/" /etc/zabbix/zabbix_agent2.conf
systemctl enable zabbix-agent2

# Регистрация в PXE-сервере (чтобы при следующей загрузке грузился с диска)
curl -s http://10.10.1.10/kickstart/register.php?hostname=$HOSTNAME\&ip=$IP

%end

# Перезагрузка после установки
reboot

Для Ceph OSD и bare-metal серверов — аналогичные файлы с другой разбивкой диска и набором пакетов. Ceph-версия использует отдельные OSD-диски без RAID, bare-metal — простую разбивку с LVM.

Cobbler и cloud-init: управление и пост-конфигурация

Cobbler — надстройка над PXE/DHCP/TFTP, которая упрощает управление профилями и системами. Вместо ручного редактирования файлов конфигурации — единый интерфейс:

# Установка Cobbler на Rocky Linux 9
sudo dnf install -y cobbler cobbler-web

# Импорт дистрибутива
sudo cobbler import --name=rocky9 --arch=x86_64 \
  --path=/var/www/html/repos/rocky9

# Создание профилей
sudo cobbler profile add --name=rocky9-kvm \
  --distro=rocky9-x86_64 \
  --autoinstall=ks-kvm.cfg \
  --autoinstall-meta='role=kvm' \
  --name-servers='10.10.1.10' \
  --name-servers-search='rudata.internal'

sudo cobbler profile add --name=rocky9-ceph \
  --distro=rocky9-x86_64 \
  --autoinstall=ks-ceph.cfg \
  --autoinstall-meta='role=ceph'

sudo cobbler profile add --name=rocky9-bare \
  --distro=rocky9-x86_64 \
  --autoinstall=ks-bare.cfg \
  --autoinstall-meta='role=bare'

# Регистрация конкретного сервера
sudo cobbler system add --name=srv-kvm-01 \
  --profile=rocky9-kvm \
  --mac-address=aa:bb:cc:dd:ee:01 \
  --ip-address=10.10.1.101 \
  --hostname=srv-kvm-01 \
  --gateway=10.10.1.1 \
  --interface=eth0

# Синхронизация (генерирует DHCP/TFTP конфиги)
sudo cobbler sync

Cloud-init для пост-установочной конфигурации. После Kickstart-установки cloud-init подхватывает дополнительную конфигурацию:

# /var/www/html/kickstart/cloud-init/user-data
#cloud-config
package_update: true
package_upgrade: true

packages:
  - htop
  - iotop
  - strace
  - lsof

runcmd:
  # Тюнинг ядра для KVM
  - echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-kvm.conf
  - echo 'net.bridge.bridge-nf-call-iptables = 0' >> /etc/sysctl.d/99-kvm.conf
  - echo 'vm.swappiness = 10' >> /etc/sysctl.d/99-kvm.conf
  - sysctl --system
  # Настройка hugepages для KVM
  - echo 'vm.nr_hugepages = 4096' >> /etc/sysctl.d/99-hugepages.conf
  - sysctl --system
  # Регистрация в Ansible inventory (через NetBox API)
  - |
    curl -s -X POST https://netbox.rudata.internal/api/dcim/devices/ \
      -H 'Authorization: Token api-token' \
      -H 'Content-Type: application/json' \
      -d "{\"name\": \"$(hostname)\", \"device_role\": 1, \"site\": 1, \"status\": \"active\"}"

final_message: "Cloud-init completed in $UPTIME seconds"

Preseed — аналог Kickstart для Debian/Ubuntu. Для клиентов с Debian-серверами мы создаём preseed-файлы:

# /var/www/html/kickstart/preseed-debian12.cfg (фрагмент)
d-i debian-installer/locale string ru_RU.UTF-8
d-i keyboard-configuration/xkb-keymap select us
d-i netcfg/choose_interface select auto
d-i mirror/http/hostname string mirror.rudata.internal
d-i partman-auto/method string lvm
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-auto/choose_recipe select atomic
d-i pkgsel/include string openssh-server curl wget
d-i preseed/late_command string \
  in-target mkdir -p /root/.ssh; \
  in-target wget -O /root/.ssh/authorized_keys http://10.10.1.10/kickstart/authorized_keys

Результаты и оптимизация производительности

После внедрения PXE + Kickstart для «РуДата»:

МетрикаДоПосле
Время установки 1 сервера40-60 мин12-15 мин
Участие инженераПолное (весь процесс)Только подключение к сети
Одновременная установка1 сервер10+ серверов параллельно
Время развёртки 50 серверов3 недели2 дня
Человеческие ошибки при установкеРегулярно0
Стандартизация конфигурацииЧастичная100%

Оптимизации производительности, которые мы применили:

  • HTTP вместо NFS для репозитория — Apache httpd раздаёт пакеты быстрее, чем NFS, при параллельных установках
  • Локальное зеркало — репозиторий Rocky Linux копируется на PXE-сервер, а не тянется из интернета
  • Раздельные VLAN — PXE-трафик выделен в отдельный VLAN, чтобы не мешать production
  • Multicast TFTP — при одновременной загрузке 10+ серверов ядро и initrd отдаются мультикастом

PXE + Kickstart — проверенное решение для bare-metal provisioning. Для облачной инфраструктуры есть Terraform и cloud-init, но для физических серверов PXE остаётся незаменимым. Если вам нужна автоматизация установки серверов — обращайтесь к нам в itfresh.ru.

Часто задаваемые вопросы

Да. Для каждой ОС создаётся свой пункт в меню загрузки (GRUB2 или pxelinux) и свой kickstart/preseed файл. Один PXE-сервер может раздавать Rocky Linux, Ubuntu, Debian, Windows (через WDS/MDT интеграцию). Нужно только скачать ядро и initrd для каждой ОС.
Для Secure Boot используется shimx64.efi — подписанный Microsoft загрузчик, который затем загружает grubx64.efi. В DHCP указываете filename shimx64.efi вместо grubx64.efi. Rocky Linux и Ubuntu официально поддерживают Secure Boot PXE. Если возникают проблемы — проще отключить Secure Boot в BIOS на этапе установки.
Три основных причины: 1) сервер не может скачать kickstart-файл — проверьте доступность HTTP-сервера из сети установки; 2) ошибка в kickstart-файле — валидируйте через ksvalidator из пакета pykickstart; 3) проблема с разбивкой диска — имена дисков могут отличаться (sda vs nvme0n1). Добавьте inst.sshd в параметры загрузки, чтобы подключиться по SSH для диагностики.
Для 5-20 серверов достаточно голого PXE + DHCP + TFTP. Cobbler оправдан при 50+ серверах и нескольких профилях: он автоматизирует генерацию конфигурации DHCP, TFTP и kickstart, предоставляет API и web-интерфейс. Альтернативы Cobbler: Foreman (тяжелее, но мощнее), MAAS от Canonical (для Ubuntu).
Два подхода: 1) через Cobbler — регистрируете MAC-адрес каждого сервера и привязываете hostname/IP; 2) через DHCP — назначаете фиксированный IP по MAC, а hostname вычисляете в %post секции kickstart-файла на основе IP-адреса. Второй способ проще, но менее гибкий.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#PXE boot#Kickstart#автоустановка Linux#TFTP#DHCP PXE#GRUB2 UEFI#Cobbler#preseed
Комментарии 0

Оставить комментарий

загрузка...