← Linux: загрузка
12 мин · средне · Урок 4 из 7

initramfs: временный корень в памяти

initramfs: временный корень в оперативной памяти.

Курица и яйцо при загрузке

К этому моменту цепочка старта уже прошла несколько рук: firmware передаёт управление загрузчику, загрузчик грузит ядро (kernel — центральная программа операционной системы, которая управляет памятью, процессами и железом). Дальше ядру нужно смонтировать настоящий корневой раздел, чтобы запустить первый процесс. И вот тут возникает тупик.

Чтобы прочитать корневой раздел, ядру нужны драйверы: модуль контроллера диска, код для RAID, поддержка LVM (Logical Volume Manager — прослойка, которая собирает физические разделы в гибкие логические тома). А эти модули лежат на том самом разделе, который ещё не смонтирован. Прочитать драйвер нельзя без драйвера.

Собрать всё в ядро статически можно, но тогда один и тот же образ не заведётся на машинах с разным железом. Каждому серверу пришлось бы собирать своё ядро. Так не делают.

Что такое initramfs

initramfs — это сжатый cpio-архив (cpio — старый формат архивации файлов), который загрузчик кладёт в память рядом с ядром. Ядро распаковывает его в файловую систему прямо в оперативной памяти. Эта ФС называется rootfs и живёт на tmpfs (tmpfs — файловая система, которая держит данные только в RAM), при собранном в ядре CONFIG_TMPFS.

Внутри архива лежит минимальный набор: несколько бинарников, нужные модули ядра и скрипт init, который знает, как найти и смонтировать настоящий корень. Заглянуть в содержимое можно, не распаковывая руками:

lsinitramfs /boot/initrd.img-$(uname -r) | head    # список файлов внутри архива

Вывод покажет знакомую структуру каталогов:

$ lsinitramfs /boot/initrd.img-6.1.0-18-amd64 | head
.
bin
conf
etc
init
lib
lib/modules/6.1.0-18-amd64/kernel/drivers/md/dm-mod.ko
scripts
usr

Там видно и модуль dm-mod.ko, тот самый драйвер device-mapper для LVM, без которого корень бы не смонтировался.

Как заглянуть внутрь руками

Формат открытый, распаковать архив можно обычными инструментами. Современный initramfs обычно сжат gzip или zstd:

mkdir /tmp/initrd && cd /tmp/initrd
zcat /boot/initrd.img-$(uname -r) | cpio -idmv   # распаковать cpio в текущий каталог
ls                                               # bin  etc  init  lib  scripts ...

После распаковки видно, что это полноценное маленькое дерево каталогов со своим /bin и /lib. Файл init в корне — точка входа, которую запускает ядро сразу после распаковки.

Переключение на настоящий корень

Скрипт init внутри initramfs грузит нужные модули, находит корневой раздел (по метке, UUID или пути) и монтирует его. Дальше происходит переключение: временный корень в памяти уступает место реальному разделу с диска. За это отвечает switch_root (или его предшественник pivot_root).

# упрощённо, так делает init внутри initramfs
mount /dev/mapper/vg-root /root     # смонтировать настоящий корень
exec switch_root /root /sbin/init   # сделать его корнем и запустить systemd

После switch_root память, которую занимал initramfs, освобождается, а управление получает первый настоящий процесс с PID 1 (обычно systemd — демон, который запускает и следит за остальными демонами по декларативным unit-файлам). tmpfs с временным корнем к этому моменту уже не нужен.

Механизм появился давно и стал стандартным способом загрузки с ядра 2.5.46. До него применяли старый initrd на основе ram-диска, но initramfs проще и гибче.

Две частые ловушки

Первая: «initramfs — это и есть корневая ФС с диска». Нет. Это отдельный временный образ в памяти, живёт секунды и существует только чтобы смонтировать настоящий корень. Настоящий / лежит на диске и подключается позже, через switch_root.

Вторая: «его можно удалить, он не нужен». Если стереть файл образа, при следующей загрузке ядро не найдёт драйверы для диска и остановится с паникой ещё до монтирования корня:

$ rm /boot/initrd.img-6.1.0-18-amd64   # так делать не надо
# после ребута:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

Образ пересобирается из установленных модулей командой update-initramfs -u (Debian/Ubuntu) или dracut (Fedora/RHEL) при обновлении ядра. Руками его обычно не трогают.

Что важно запомнить

initramfs — сжатый cpio-архив, который ядро распаковывает в rootfs на tmpfs в оперативной памяти.

Он решает проблему курицы и яйца: держит драйверы (диск, LVM), нужные чтобы смонтировать настоящий корень.

lsinitramfs показывает содержимое, zcat ... | cpio -idmv распаковывает руками.

После монтирования реального корня ядро делает switch_root и запускает PID 1. Механизм стандартен с ядра 2.5.46.

Это не корень с диска и удалять его нельзя: без него будет kernel panic на монтировании корня.

В следующем уроке — что делает первый процесс: systemd, unit-файлы и параллельный запуск сервисов.

Прошли материал до конца? Отметьте урок пройденным.