Блог ·
Від відповіді DHCP до готової інсталяції
Мережеве завантаження, частина друга. Що буває після пропозиції: скрипт завантаження, файл відповідей, зворотний виклик і хто публікує контрольні суми.
Автор: Provibr
Змусити машину прийняти пропозицію мережевого завантаження це та частина, про яку пишуть усі. Ми теж про неї писали, після того як утратили тиждень на адресі призначення відповіді proxy-DHCP.
Про частину після цього майже не пишуть, а саме там живуть справжні відмови. Машина, яка завантажилася й далі вічно сидить на питанні, гірша за ту, що не завантажилася взагалі, бо має вигляд поступу. Це друга половина: що має бути істинним між приходом пропозиції та появою запрошення до входу, і що з цього падає мовчки.
Пʼять речей, які роздаються
Щойно клієнт має пропозицію й файл завантаження, автоматична інсталяція це пʼять артефактів. Жоден із них не є необовʼязковим, а останній це той, який люди пропускають.
| № | Що | Хто роздає | Як падає |
|---|---|---|---|
| 1 | Скрипт завантаження | HTTP | Машина падає в оболонку |
| 2 | Ядро | HTTP | Завантаження переривається |
| 3 | Initrd | HTTP | Завантаження переривається |
| 4 | Файл відповідей | HTTP | Інсталятор ставить питання і чекає |
| 5 | Зворотний виклик про завершення | Встановлена система | Усе висить до настання дедлайну |
Цікавий стовпчик це останній, «Як падає». Пункти з 1 до 3 падають гучно, на екрані, так, що хтось помітить. Пункти 4 і 5 падають як інсталяція, яка має вигляд робочої й ніколи не завершується.
Скрипти завантаження і проблема плейсхолдера
Скрипт завантаження має називати абсолютні URL, а знати їх під час запису профілю він не може: адреса того, хто роздає файли, залежить від сегмента, у якому машина піднялася.
Тож профіль містить плейсхолдер, який підставляють у момент роздачі. Наш це @@PROVIBR_BASE@@, і його форма є свідомим вибором, а не питанням стилю.
Очевидною формою було б ${BASE}. Це рівно неправильно, бо iPXE розгортає ${...} сам. Підстановка, яка не сталася, стає порожнім рядком, а не помилкою, і ви опиняєтеся перед
chain http:///vmlinuzі гадаєте, що не так із вашим вебсервером. Роздільник, якого завантажувач не впізнає, перетворює мовчазну невдачу підстановки на видиму.
Три командні рядки ядра, які мають значення, якщо зняти брендування:
# Ubuntu (subiquity)
kernel <kernel> initrd=<initrd> ip=dhcp autoinstall ds=nocloud;s=<dir>/ --- || goto failed
# Debian (preseed)
kernel <kernel> initrd=<initrd> auto=true priority=critical ip=dhcp url=<file> DEBIAN_FRONTEND=text --- quiet || goto failed
# RHEL family (Anaconda)
kernel <kernel> initrd=<initrd> ip=dhcp inst.repo=<tree> inst.ks=<file> inst.text || goto failedТри інсталятори, три геть різні словники для тієї самої ідеї, і аргумент, що несе файл відповідей, у кожному пишеться інакше. ds= бере каталог; url= та inst.ks= беруть файл. Переплутайте це, і ви отримаєте інсталятор, який завантажується, а далі ставить перше питання.
Чотири ключі autoinstall, що вирішують, чи вона завершиться
Autoinstall від Ubuntu заслуговує на власний абзац, бо в ізольованому сегменті чотири ключі відділяють інсталяцію, яка завершується, від тієї, яка ні, і жоден із них не стосується дисків чи користувачів:
interactive-sections: []: без нього subiquity все одно зупиниться, щоб щось спитати.refresh-installer.update: false: без нього він спершу піде шукати новіший інсталятор.apt.fallback: offline-install: без нього він чекатиме на архів, перш ніж здатися.drivers.install: false: той самий клас проблеми, той самий результат.
Відмова в кожному випадку та сама: екран, який має зайнятий вигляд. Помилки немає, бо з погляду інсталятора нічого не пішло не так.
Для носія є відповідний прапорець. Netboot-initrd від Ubuntu розпаковує носій інсталяції в tmpfs і встановлює з нього; якщо не сказати йому, де той носій, він піде шукати його в інтернеті. У сегменті без каналу назовні це різниця між роботою й чотирма хвилинами нічого, за якими йде запрошення busybox.
Зворотний виклик, якого ніхто не пише
Пункт 5 у списку це один рядок у скрипті після встановлення, який запитує URL, і це найчастіше відсутня деталь у саморобних збірках.
Без нього немає події, яка означає завершено. Інсталятор перезавантажується, машина піднімається, а система, яка почала інсталяцію, не має про це уявлення, тож чекає до свого дедлайну й далі повідомляє про тайм-аут на машині, що встановилася бездоганно.
Дві деталі роблять це менш прикрим, ніж звучить. Перша: постачайте гачок у шаблоні, а не документуйте його, щоб той, хто пише власний скрипт після встановлення, не мусив знати про його існування. Друга: майте гачок і на відмову, а не лише на успіх: інсталяція, яка падає о 04:00 і каже про це, це інший досвід підтримки, ніж та, що просто затихла.
І тримайте два годинники, а не один. Команда, що починає інсталяцію, має завершуватися, щойно слухачі підняті й сесію прийнято, а не коли інсталяція скінчилася; у нас на це дедлайн 90 секунд, проти бюджету інсталяції в одну годину, який тримають обидві сторони. Один дедлайн на обидва означає або завдання, що годину висить в інтерфейсі, нічого не роблячи, або інсталяцію, вбиту за те, що вона триває стільки, скільки тривають інсталяції.
Хто з вендорів публікує контрольну суму, виміряно
Якщо машина тягне ядро та initrd по HTTP із дзеркала, щось має перевірити те, що прийшло. Спосіб це закріпити sha256 у профілі й перевірити після завантаження, там, де відбувається завантаження.
Це працює, лише якщо вендор її публікує. Ми припустили, що відповідь «здебільшого ні», записали це, і воно виявилося хибним у трьох випадках із чотирьох. Що публікується насправді, виміряно 2026-09-02:
| Вендор | Ядро + initrd для netboot | Де |
|---|---|---|
| Debian | Так | SHA256SUMS поруч із installer-amd64/current/images/ |
| Родина RHEL | Так | [checksums] у .treeinfo поруч із деревом |
| Ubuntu (ISO live server) | Так | SHA256SUMS поруч із випуском |
| Ubuntu (ядро + initrd для netboot) | Ні | У каталозі netboot немає файла контрольних сум, і тарбол не вказано також у сумах випуску |
Ціною того хибного припущення був не простій; було гірше, і по-тихому. Активи, які можна було закріпити, лежали позначені як неперевірні, а профілі повідомляли про себе як про непридатні до встановлення, поки вендор публікував відповідь у всіх на очах. Чотири артефакти з пʼяти у перших двох профілях.
Поведінку на випадок, коли контрольної суми справді немає, варто спроєктувати навмисно. У нас закріплення лишається порожнім, актив позначається як очікуваний, а профіль повідомляє про себе як про непридатний до встановлення, поки адміністратор не вставить хеш. Це навмисно гучніше, ніж завантажити його все одно. Неперевірене ядро, узяте по HTTP із дзеркала, це найцінніше місце для атаки на систему провізіонінгу, а «ми не змогли це перевірити, тож зробили все одно» не є політикою.
Що дозволено означати слову «підтримується»
Ми постачаємо десять базових профілів: Ubuntu Server 24.04 і 26.04, Debian 12 і 13, Rocky Linux 9 і 10, AlmaLinux 9 і 10, CentOS Stream 10, Fedora Server 44.
Статус підтримки, прикріплений до кожного, обчислюється, а не вводиться. Профіль може називати себе підтримуваним, лише коли він має перевірений запуск на обох шляхах мікропрограми, BIOS і UEFI. Один із двох дає «попередній перегляд». Жоден не дає «не підтримується».
Зробити це правилом, а не полем, варте невеликої кількості коду. Мітка, введена руками, варта рівно стільки, скільки уважності мав той, хто її вводив, а це мітка, покладаючись на яку клієнт ставить машину.
А отже, варто чітко сказати, де це нас лишає сьогодні. Ubuntu Server 26.04 і Debian 13 встановилися повністю без нагляду в ізольованому сегменті, на машині з BIOS. Шлях UEFI полагодили в тому самому раунді, а полагодити це не те саме, що запустити. Тож на момент написання жоден стандартний профіль не є maintained, а профілі родини RHEL не запускалися на справжній машині взагалі: їх написано з документації вендорів і звірено зі справжніми вихідними файлами, і це слабша заява, ніж має вигляд ззовні.
Окремо: пропонувати мережеве встановлення як спосіб створити нову машину в нашій платформі усталено вимкнено, в очікуванні рівно однієї речі: справжньої машини, яка так себе встановить, на справжній мікропрограмі. Шлях, який існує і використовується, це перевстановлення поверх наявної машини. Прапорець функції, увімкнений тому, що код написано, а не тому, що річ спостережено в роботі, породжує кнопку замовлення, яка застрягає на півдорозі в першого ж справжнього клієнта.
Дрібниці, кожна з яких коштує пів дня
- Перевіряйте шляхи файлів, які роздаєте. Ніякої початкової скісної риски, ніяких
.., ніяких зворотних скісних рисок, один клас символів. Те, що роздає файли, стоїть усередині чиєїсь мережі, і за ним є файлова система. - Вимарюйте рядок аудиту. Записуйте, який файл роздано і чи ніс він секрет, ніколи не вміст. Кожен, кому потрібен вміст, може відрендерити профіль наново.
- Не дозволяйте файлу відповідей бути другим джерелом правди про носій. І аргумент ядра, і файл відповідей називають, звідки беруться пакунки; вивести обидва з одного налаштування це єдиний спосіб тримати їх рівними.
- Припускайте, що за консоллю ніхто не стежить. Кожен вибір вище це вибір про те, що станеться, коли інсталяція на шостій хвилині з восьми, а людини в кімнаті немає.
Це друга частина статті про те, чому мережеве завантаження UEFI падає там, де BIOS працює, і вона вийшла з побудови мережевого встановлення в Provibr. Подробиці є в документації з мережевого завантаження.