Mateusz Adamowski Szkolenia

Initramfs

co się dzieje, zanim wstanie system?

Mateusz Adamowski

SysOps/DevOps MeetUp #89 2026
Warszawa, 2026-11-26


O mnie


initramfs

Komu to potrzebne?


Error


Error


Error


Czy initramfs jest potrzebny?

Często nie

Ale po kolei…


Start systemu


BIOS

Umie wczytać MBR
(446 bajtów)

Nie rozumie tablicy partycji, systemów plików


UEFI


BIOS lub UEFI wczytuje bootloader (GRUB)


GRUB

(w ograniczonym stopniu też: LVM, RAID, LUKS)


GRUB

  1. wczytuje plik konfiguracyjny
  2. ładuje kernel (i initrd)

Kernel

  1. uruchamia się
  2. montuje dysk (root=)
  3. uruchamia proces init (PID 1)

Jak dostać się do dysku systemowego?

dostanie się do dysku wymaga modułów

🔃

moduły są na dysku


initramfs


initrd?


ramdisk vs ramfs


struktura initrd


initrd


struktura initramfs


cpio?


initramfs


ls


skrypt init


skrypt init

# ...
# przygotuj /root
# ...

exec run-init /root /bin/init "$@"

Busybox


Narzędzia


cryptroot

Please unlock disk sda2_crypt: ...

Szyfrowany dysk wymaga hasła…

… wpisanego lokalnie


Use case #1:

zdalne wprowadzanie hasła


KVM / IPMI


zdalny dostęp do initramfs


dropbear


dropbear


dropbear


Dropbear


initramfs w Debianie


Rozbudowywanie initramfs


conf.d


przykład

WLAN_SSID=Moja_siec
WLAN_PASS=tajn3hasl0

export WLAN_SSID WLAN_PASS

hooks


przykładowy hook

#!/bin/sh

[ "$1" = "prereqs" ] && exit 0

. /usr/share/initramfs-tools/hook-functions

copy_exec /usr/bin/wg
copy_exec /bin/busybox /bin/busybox.full

hook-functions


skrypty


    init-top        (przed załadowaniem modułów)
        ↓
    init-premount
        ↓
    local-top
        ↓
    local-premount
        ↓
    local-bottom    (po zamontowaniu /)
        ↓
    init-bottom
        ↓
    *** start normalnego systemu ***

szablon skryptu

#!/bin/sh

PREREQ="udev"

prereqs() {
    echo "$PREREQ"
}

case "$1" in
    prereqs)
        prereqs
        exit 0
    ;;
esac

szablon skryptu (oneliner)

#!/bin/sh

test "$1" = "prereqs" && echo "udev" && exit 0

Uwaga

Krok służy ustaleniu zależności (kolejności) uruchamiania skryptów.


Uwaga

Skrypt jest uruchamiany również w trakcie budowania initramfs (na hoście).

Parametr: prereqs


Use case #2

wireguard


hook

...

copy_exec /usr/bin/wg

manual_add_modules wireguard

copy_file conffile /etc/initramfs/wg0.conf /conf/wg0.conf

wg


skrypt (init-premount)

...

ip link add "$interface" type wireguard
ip link set "$interface" up
wg setconf "$interface" /conf/wg0.conf

ip address add "$addr" dev "$interface"
ip route add "$route" dev "$interface"

wg


Use case #3

wifi


hook

...

copy_file conffile /etc/initramfs-tools/wpa_supplicant.conf \
            /conf/wpa_supplicant.conf

copy_exec /usr/sbin/iw
copy_exec /usr/sbin/wpa_supplicant
copy_exec /usr/sbin/wpa_cli

manual_add_modules mwifiex_sdio

skrypt (init-premount)

...

modprobe "$WLAN_MODULE"
sleep 5

for TTT in 4 8 16 32; do
    wpa_supplicant -B -i wlan0 -c /conf/wpa_supplicant.conf
    ipconfig -t "$TTT" -d wlan0 && exit 0
    wpa_cli -p /run/wpa_supplicant -i wlan0 terminate
    echo "Wifi retrying"
    sleep "$TTT"
done

Use case #4

notyfikacje


ntfy.sh

ntfy


conf.d/ntfy

NTFYSH_HOSTNAME="mojserwer01"
NTFYSH_TOPIC="mati_homelab"

export NTFYSH_HOSTNAME
export NTFYSH_TOPIC

skrypt (init-premount)

(
  attempts=10
  while [ "$attempts" -gt 0 ]; do
    wget -q -T 5 -O /dev/null \
      --no-check-certificate \
      --post-data="$(uname -r)" \
      --header="Title: ${NTFYSH_HOSTNAME}: dropbear ready" \
      --header='Tags: teddy_bear' \
      "https://ntfy.sh/${NTFYSH_TOPIC}" && break

    attempts=$((attempts - 1))
    [ "$attempts" -gt 0 ] && sleep 5
  done
) &

ntfy


Więcej pomysłów


Initramfs from scratch


Budowa własnego initramfs od zera


trywialny init

#!/bin/sh

echo "Welcome to myinitramfs!"
sh

budowa initramfs

mkdir -p initramfs && cd initramfs
mkdir -p bin
cp "$SRC/busybox" bin/busybox
cp "$SRC/init" bin/init
ln -s busybox bin/sh
find . | cpio --owner=0:0 -H newc -o > ../initrd

ntfy


Diskless?

A gdyby tak nie montować dysku i zostać w RAM-ie na zawsze?


Diskless

(aka LiveCD)


przejście do nowego systemu

mount -t proc proc /proc
memsize="$(sed -ne '/^MemTotal/s/^.*: *\(.*\) kB$/\1/p' /proc/meminfo)"
umount /proc

mkdir -p /newroot
mount -t tmpfs -o "size=${memsize}k,mode=0755" tmpfs /newroot

tar -x -C /newroot --strip-components=1 < /rootfs.tar

exec /bin/run-init /newroot /sbin/init "$@"

A może squashfs?

mkdir -p /rootfs-ro
mount -t squashfs -o loop,ro /rootfs.squashfs /rootfs-ro
mkdir -p /overlay /newroot

memsize="$(sed -ne '/^MemTotal/s/^.*: *\(.*\) kB$/\1/p' /proc/meminfo)"
mount -t tmpfs -o "size=${memsize}k,mode=0755" tmpfs /overlay

mkdir -p /overlay/upper /overlay/work
mount -t overlay overlay -o \
  lowerdir=/rootfs-ro,upperdir=/overlay/upper,workdir=/overlay/work \
  /newroot

exec /bin/run-init /newroot /sbin/init "$@"

Co dalej?


Zalety


dracut


systemd w initramfs


UKI

Unified Kernel Image


ukify

ukify build \
    --linux=kernel-x.y.z" \
    --initrd=initrd-x.y.z.gz" \
    --cmdline="console=tty0" \
    --output="mojsystem.efi"

kexec

kexec -l inny-kernel \
        --append=...cmdline... \
        --initrd=inny-initrd

Szkolenia

https://www.sysopspolska.pl/szkolenia


Materiały

mateusza-szkolenia.github.io


Koniec