Learning Platform
Глоссарий Troubleshooting
Урок 15.02 · 18 мин
Начальный
GRUBBootloaderLinuxRecovery

GRUB2 — выбор kernel и rescue mode

Когда сервер загружается и вы видите на чёрном экране меню с вариантами kernel, “Advanced options for Ubuntu”, “Memory test” — это GRUB. Grand Unified Bootloader — де-факто стандартный bootloader для Linux на x86_64. Он загружает kernel, передаёт ему параметры, и (важно для админа!) даёт точку входа в rescue mode, когда обычная загрузка сломалась.

В этом уроке: что GRUB делает на каждом шаге, как редактировать его конфиг (/etc/default/grub), что такое GRUB shell и зачем уметь править kernel cmdline на лету — это спасает 4-утренние инциденты, когда сервер падает в loop восстановления.


GRUB в архитектуре загрузки

Когда вы изучали урок 13.1, мы говорили о цепочке firmware -> bootloader -> kernel. GRUB — это bootloader. На современных серверах:

  • Legacy BIOS-машины. GRUB живёт в MBR (первые 512 байт диска) + дополнительные стадии в первых ~30 КБ диска. Не помещается в 512 байт сам GRUB — поэтому он разбит на стадии (stage1, stage1.5, stage2).
  • UEFI-машины. GRUB живёт в ESP (EFI System Partition) как файл /boot/efi/EFI/<distro>/grubx64.efi. Firmware загружает этот файл напрямую.

В обоих случаях после старта GRUB читает /boot/grub/grub.cfg — сгенерированный файл со всеми entries (kernel-варианты, рекавери, memory test).

GRUB между firmware и kernel
UEFIFirmware -- читает EFI variables, находит grubx64.efi в ESP, загружает и передаёт control
grubx64.efiГлавный GRUB binary в формате PE32+ (EFI app). Знает как читать ext4/xfs/btrfs, найти /boot/grub/grub.cfg
grub.cfgФайл /boot/grub/grub.cfg -- сгенерирован из /etc/default/grub + /etc/grub.d/*. Сами не редактируем, только через update-grub
User selectПользователь выбирает entry (или таймаут истёк -- default). Можно нажать 'e' для редактирования entry перед запуском
Load kernelGRUB загружает в RAM vmlinuz и initrd, передаёт kernel cmdline (root=UUID=..., ro, quiet, splash, и любые custom параметры)
bootGRUB передаёт control kernel (jumps to entry point). С этого момента kernel самостоятельно работает

Файлы конфигурации

Базовая структура файлов GRUB на Ubuntu/Debian:

/etc/default/grub              # admin-edited config (источник правды для админа)
/etc/grub.d/                   # скрипты, которые генерируют grub.cfg
    00_header                  # заголовок, общие настройки
    05_debian_theme            # стилизация
    10_linux                   # автогенерация entries для всех kernel
    20_linux_xen
    30_os-prober               # entries для других OS (Windows если dual-boot)
    40_custom                  # для custom entries
    41_custom                  # для custom entries
/boot/grub/grub.cfg            # сгенерированный config (не редактировать руками!)

Главное правило: не редактируйте /boot/grub/grub.cfg напрямую. Он перегенерируется при каждом kernel-upgrade и затрёт ваши изменения. Редактируйте /etc/default/grub и/или скрипты в /etc/grub.d/, потом sudo update-grub.


/etc/default/grub: что внутри

$ sudo cat /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR="Ubuntu"
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""

Что значит каждая опция:

  • GRUB_DEFAULT=0 — индекс default-entry (0 = первый = самый новый kernel).
  • GRUB_TIMEOUT=10 — сколько секунд показывать меню (0 = сразу boot, -1 = ждать вечно).
  • GRUB_TIMEOUT_STYLE=hidden — “hidden” не показывает меню, “menu” показывает.
  • GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" — параметры kernel для нормальной загрузки.
  • GRUB_CMDLINE_LINUX="" — параметры для ВСЕХ entries (включая recovery).

После любых изменений:

sudo update-grub          # Debian/Ubuntu
# или:
sudo grub-mkconfig -o /boot/grub/grub.cfg     # RHEL/Fedora/Arch
# или (UEFI с alternative configdir):
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Kernel command line: что туда писать

GRUB_CMDLINE_LINUX_DEFAULT и GRUB_CMDLINE_LINUX — это параметры, которые GRUB передаст kernel. Kernel-cmdline — мощный инструмент.

Полезные параметры:

# Не показывать заставку, видеть все kernel-сообщения:
GRUB_CMDLINE_LINUX_DEFAULT=""    # убрать quiet и splash

# Загрузка в single user mode (rescue):
single

# Загрузка с другим init (например debug shell):
init=/bin/bash

# Не активировать swap:
noswap

# Игнорировать reserved memory (если плохо считается):
mem=8G

# Отключить watchdog:
nowatchdog

# Включить kernel debug:
debug

# Для production: serial console (полезно когда нет видеовывода):
console=ttyS0,115200n8

# Ограничить число CPU (для debug):
maxcpus=1

# IOMMU включить (для passthrough):
intel_iommu=on iommu=pt

# Отключить SELinux (RHEL):
selinux=0

# Включить Magic SysRq (для аварийного восстановления):
sysrq=1

После изменения /etc/default/grub:

sudo update-grub
# Проверить:
grep '^[[:space:]]*linux' /boot/grub/grub.cfg | head -3
# Увидите: linux /boot/vmlinuz-... root=UUID=... ro quiet splash

Динамическое редактирование на boot

Самая полезная функция GRUB на практике: редактирование entry перед запуском. Сценарий: вы пришли с pager-alert, что что-то сломалось, надо запустить single-user mode — но нет времени менять config.

Шаги:

  1. Перезагружаете сервер.
  2. На GRUB меню (если оно не появилось — держите Shift при boot или нажимайте Esc).
  3. Стрелками выбираете нужный kernel.
  4. Нажимаете e — открывается редактор.
  5. Стрелкой вниз идёте к строке linux /boot/vmlinuz....
  6. В конце строки добавляете нужный параметр, например single или init=/bin/bash.
  7. Ctrl-X или F10 — загрузить с этими параметрами (для одного boot).
TIP

Эта правка одноразовая — следующий boot уже без неё. Это хорошо: если “single” не помог, после reboot обычная загрузка попробует снова.

Самые частые добавления для рекавери:

single                    # systemd запустит rescue.target -- minimal services + login
init=/bin/bash            # пропустить init вообще, прямо bash как PID 1
emergency                 # systemd emergency.target -- даже базовых mounts нет
systemd.unit=rescue.target    # systemd альтернатива single
nomodeset                 # без видео-driver (если экран чёрный из-за GPU)

GRUB shell — когда даже меню не появилось

Если GRUB вообще не может найти ваш kernel (например, корруптнут grub.cfg) — появится GRUB shell: grub> prompt. Это полноценный мини-shell с командами навигации по дискам.

grub> ls
(hd0) (hd0,gpt1) (hd0,gpt2) (hd0,gpt3)

grub> ls (hd0,gpt2)/
boot/  bin/  dev/  etc/  home/  lib/  ...

grub> set root=(hd0,gpt2)
grub> linux /boot/vmlinuz-6.5.0-21-generic root=/dev/sda2
grub> initrd /boot/initrd.img-6.5.0-21-generic
grub> boot

Что делаем:

  1. ls без аргументов — список дисков.
  2. ls (hd0,gpt2)/ — список файлов в корне второго раздела первого диска.
  3. Найдя свой /boot, устанавливаем root, загружаем kernel и initrd, делаем boot.

Это сценарий когда grub.cfg сломан. После успешного boot — chroot в систему и update-grub, grub-install.

Маппинг устройств в GRUB:

  • (hd0) — первый диск целиком.
  • (hd0,gpt1) — первый раздел первого диска (GPT-схема).
  • (hd0,msdos1) — первый primary раздел (MBR/MSDOS-схема).
  • (cd0) — CD-ROM.

/etc/grub.d/40_custom — свои entries

Если нужно добавить custom entry в меню GRUB (например, для альтернативного kernel или ОС, которую os-prober не нашёл):

$ sudo vim /etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# Below is the actual code

menuentry "My Custom Kernel" {
    set root=(hd0,gpt2)
    linux /boot/vmlinuz-custom root=/dev/sda2 ro quiet
    initrd /boot/initrd-custom
}

menuentry "Memtest86+" {
    set root=(hd0,gpt1)
    linux16 /memtest86+.bin
}

Не забудьте сделать файл executable: chmod +x /etc/grub.d/40_custom. После update-grub ваши entries появятся в grub.cfg в конце.


grub-install — переустановка bootloader

Иногда GRUB надо переустановить (после восстановления диска, изменения partition layout, dual-boot install Windows перезатёр MBR):

# BIOS-машина (на MBR-диск):
sudo grub-install /dev/sda
sudo update-grub

# UEFI-машина:
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu
sudo update-grub

--bootloader-id — имя поддиректории в ESP (/boot/efi/EFI/<id>/) и метка в efibootmgr.

# Проверить, что попало в EFI variables:
sudo efibootmgr -v
Boot0001* ubuntu  HD(1,GPT,...,800,100000)/File(\EFI\ubuntu\shimx64.efi)

Защита GRUB паролем

Для серверов в shared-environments часто хотят защитить GRUB паролем — чтобы не давать access к single-mode без admin’а:

# Сгенерировать хеш пароля:
sudo grub-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.AAAA...

# Добавить в /etc/grub.d/40_custom:
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.AAAA...

sudo update-grub

Теперь редактирование entry или GRUB shell потребует пароль.

WARNING

GRUB-пароль — НЕ защита от physical attacker. Кто-то с физическим доступом всегда может загрузиться с LiveCD, замаунтить ваш диск, прочитать данные. Для serious security — full disk encryption (LUKS).


Дебаг проблем GRUB

Симптом: GRUB меню не появляется.

# Принудительно показать меню:
sudo sed -i 's/GRUB_TIMEOUT_STYLE=hidden/GRUB_TIMEOUT_STYLE=menu/' /etc/default/grub
sudo sed -i 's/GRUB_TIMEOUT=0/GRUB_TIMEOUT=10/' /etc/default/grub
sudo update-grub

Симптом: “error: file ‘/boot/vmlinuz-…’ not found”.

Возможно, удалили старый kernel но он ещё в grub.cfg. Решение: sudo update-grub пересоздаст.

Симптом: после Windows install Linux исчез из меню.

Windows перезаписал MBR/UEFI boot order. Решение: загрузиться с Linux LiveUSB, chroot, grub-install, update-grub.

Симптом: GRUB rescue prompt (“grub rescue>”).

Это самый минимальный GRUB shell. Файловая система сломана или удалены критичные файлы. Команды очень ограничены, нужно вручную загружать stage2:

grub rescue> ls
(hd0) (hd0,gpt1) (hd0,gpt2)
grub rescue> set root=(hd0,gpt2)
grub rescue> set prefix=(hd0,gpt2)/boot/grub
grub rescue> insmod normal
grub rescue> normal
# Если повезло -- появится нормальный GRUB меню

После этого с LiveCD сделать chroot и grub-install, update-grub.


Попробуй сам

# 1. Посмотреть текущий config (только источник правды):
cat /etc/default/grub

# 2. Посмотреть сгенерированный grub.cfg (только информативно):
grep '^menuentry\|^[[:space:]]*linux' /boot/grub/grub.cfg | head -10

# 3. Узнать какой kernel дефолтный:
sudo grub-editenv list

# 4. (При следующем boot) показать меню принудительно:
# Подержать Shift при загрузке или нажимать Esc

# 5. Сделать показ меню постоянным:
sudo sed -i 's/GRUB_TIMEOUT_STYLE=hidden/GRUB_TIMEOUT_STYLE=menu/' /etc/default/grub
sudo update-grub

# 6. Изменить timeout на 5 секунд:
sudo sed -i 's/GRUB_TIMEOUT=10/GRUB_TIMEOUT=5/' /etc/default/grub
sudo update-grub

# 7. Что в EFI variables (только UEFI):
sudo efibootmgr -v

# 8. Сгенерировать grub-пароль (не применять, просто посмотреть):
grub-mkpasswd-pbkdf2
# Тренировка ради тренировки

Проверка знанийKnowledge check
После apt upgrade обновили kernel -- 6.5.0-21 на 6.5.0-22. Перезагружаюсь -- сервер падает в kernel panic 'unable to mount root'. Хочу загрузиться со старым 6.5.0-21 чтобы починить, но GRUB меню вообще не показывается -- сразу загружается новый сломанный kernel. Как принудительно попасть в меню?
ОтветAnswer
Это популярная боль: GRUB настроен с GRUB_TIMEOUT_STYLE=hidden и GRUB_TIMEOUT=0 -- меню скрыто и таймаут 0. Стандартное поведение многих современных дистрибутивов. Но GRUB всё равно даёт возможность принудительно открыть меню. Как показать меню принудительно: 1. Самый универсальный способ -- удерживать Shift сразу после POST (когда BIOS/UEFI screen уходит). На некоторых системах работает Esc. Этот hold-key event GRUB ловит и показывает меню несмотря на hidden setting. 2. Кнопка Power -- если систему перезагружают через короткое нажатие, при следующем boot GRUB зачастую покажет меню. Это поведение -- 'I detected interrupted boot', GRUB добавляет recovery menu. 3. Если ничего не работает -- IPMI/iLO/iDRAC (server out-of-band management) даёт виртуальную клавиатуру. Можно подключить и спокойно держать Shift. 4. С LiveUSB -- загрузиться с LiveCD/USB, chroot в систему, поменять /etc/default/grub: GRUB_TIMEOUT_STYLE=menu GRUB_TIMEOUT=10 sudo update-grub После reboot меню гарантированно покажется. Когда меню появилось: 1. Стрелками выбрать 'Advanced options for Ubuntu' (или аналог). 2. Внутри -- список kernel и рекавери-entries. 3. Выбрать предыдущий kernel '6.5.0-21' (он там должен быть -- apt не удаляет старые kernel автоматически). 4. Boot. Если работает -- система загрузилась со старым kernel: 1. Понять что сломалось в новом: - dpkg -l linux-image-6.5.0-22 -- стоит ли пакет - sudo update-initramfs -u -k 6.5.0-22 -- пересобрать initramfs (часто это исправление) - sudo dpkg-reconfigure linux-image-6.5.0-22 -- переконфигурить 2. Если можно -- понять root cause: - dmesg -k -b -1 -- что говорил kernel при предыдущей попытке - journalctl -b -1 -k 3. После фикса -- update-grub и reboot, проверить новый kernel снова. Profilaktika для будущего: - Перед kernel-upgrade на production -- снимать снапшот VM/иметь LiveUSB. - GRUB_TIMEOUT > 0 на server-системах -- даёт окно для рекавери. - Сохранять старые kernel пакеты несколько версий назад (apt по default так и делает). - Тестировать критичные сервисы после kernel-upgrade.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 6. Какой файл считается источником правды для конфигурации GRUB?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4