Kexec: rychlý restart bez restartu

25. 11. 2020
Doba čtení: 4 minuty

Sdílet

 Autor: Depositphotos
Linuxové jádro už dlouho obsahuje podporu volání kexec, které umožňuje nahradit aktuálně běžící jádro jiným. Ukážeme si, jak se takové volání používá a k čemu může být dobré.

Systémové volání kexec umožňuje Linuxu nahradit aktuálně běžící jádro novým. Hned ze začátku je však třeba uklidnit přehnaná očekávání, která tato slovníková definice může způsobit. Jedná se totiž o analogii běžného unixového volání exec, které tvoří spolu s voláním fork běžný způsob vzniku nového procesu. Každý proces, kromě procesu s číslem 1, který je vytvořen jádrem po startu, vzniká tak, že se existující proces voláním fork rozdvojí na pár rodiče a dítě, a zatímco rodič pokračuje dál, dítě vzápětí zavolá funkci exec, čímž nahradí kód původního procesu kódem nového.

V případě výměny jádra odpadá část s rozdvojením procesu, protože jádro není proces a běží vždy právě jedno. Jde tak pouze o nahrazení jádra novým, přičemž při spuštění nového jádra staré přestane existovat a ztratí se i veškerý jeho vnitřní stav. Protože vnitřním stavem jádra jsou i všechny běžící procesy a připojené souborové systémy, znamená výměna jádra prakticky restart systému. Také se dá říct, že volání kexec dělá z Linuxu zavaděč pro jiný Linux.

Praktické použití

Analogie se zavaděčem odpovídá i tomu, jak se dá kexec prakticky použít. Je k tomu potřeba stejnojmenná utilita z balíčku kexec-tools. Ta pracuje podobně jako třeba zavaděč GRUB ve dvou krocích − nejprve je do paměti nahrán obraz jádra, jeho parametry a případně i startovací RAMdisk a pak je v druhém kroku jádro spuštěno.

První krok provedeme třeba takto:

# kexec --load /boot/vmlinuz --initrd /boot/initramfs --append root=/dev/sda1 

Pomocí přepínače --reuse-cmdline můžeme novému jádru předat stejné parametry příkazového řádku, jako používá aktuálně běžící jádro, obdobně lze předat i aktuálně používaný startovací RAMdisk. Tady je však potřeba upozornit, že startovací RAMdisky (přesněji řečeno initramfs) obvykle obsahují moduly pro příslušné jádro, takže pokud má být nahráno jiné než aktuálně běžící jádro, pravděpodobně nebude se zachováním starého RAMdisku fungovat. Pro distribuce založené na Debianu lze s výhodou využít symbolických odkazů na aktuální jádro a RAMdisk přímo v kořeni souborového systému, takto:

# kexec --load /vmlinuz --initrd=/initrd.img --reuse-cmdline 

Druhý krok nemusíme řešit

Jádro máme zavedeno, zbývá ho tedy jen spustit příkazem kexec --exec. Tohle ale doma nezkoušejte. Příkaz totiž zafunguje okamžitě a začne startovat nové jádro, zatímco to staré − se spuštěnými procesy, připojenými souborovými systémy a nezapsanými diskovými buffery − přestane existovat. Prakticky tedy dojde k ekvivalentu stisku tlačítka reset.

Je tedy potřeba tento příkaz volat až po řádném ukončení všech procesů a odpojení všech disků, zkrátka jako při klasickém měkkém restartu počítače. Tady přichází dobrá zpráva: toto už je v distribucích zařízeno. Všechny distribuce, které jsem testoval, mají ve své vypínací sekvenci na samotném konci test, zda má kexec připravené nové jádro ke spuštění. Pokud ne, je proveden klasický restart, pokud ano, je spuštěno nové jádro a restart je tak zkrácen na zcela minimální dobu.

Poznámku si ještě zaslouží příkaz systemctl kexec. Ten by měl zcela automaticky provést restart pomocí kexec, jeho funkce ovšem závisí na použití zavaděče systemd-boot. Žádný systém s tímto zavaděčem nemám po ruce, takže jsem tuto funkci nemohl vyzkoušet.

K čemu lze rychlý restart použít

Může se zdát, že výhoda v používání volání kexec není velká. Zejména moderní laptopy zkrátily POST na naprosté minimum, takže rozdíl mezi restartem a použitím volání kexec bude jen ve zdržení odpočtem v menu GRUBu. Podobná situace bude platit pro virtuální servery, jako na této ukázce. Přesto se najdou případy, kdy se použití kexec může vyplatit.

Tím prvním je použití s plně šifrovaným diskem, kdy je šifrován i oddíl /boot a heslo je tedy potřeba zadat už do GRUBu, aby se vůbec dostal k šifrovanému obrazu jádra a startovacímu RAMdisku. Protože GRUB nedokáže předat rozšifrovaný oddíl startujícímu jádru, používá se v tomto nastavení trik, kdy je klíč schován do (šifrovaného) startovacího RAMdisku. Díky tomu není potřeba zadávat heslo dvakrát. Při použití kexec pak není nutné heslo zadávat vůbec, protože je předáno přímo pomocí startovacího RAMdisku.

Druhou velkou výhodu představuje použití volání kexec na profesionálním serverovém hardwaru. Snad každý, kdo se někdy osobně prováděl restart ve studené uličce datacentra, dokáže potvrdit, že POST u těchto serverů trvá nekonečně dlouho − pět minut je naprosté minimum. Pokud během výpadku serveru dojde k výpadku poskytované služby, je dost velký rozdíl, jestli ten výpadek bude trvat desítky sekund nebo jednotky minut.

ict ve školství 24

Aktualizace mikrokódu se bez plného restartu neobejde

Existuje jedna výjimka, kdy restart pomocí volání kexec není plnohodnotnou náhradou běžného restartu. Je to v případě, kdy obraz initramfs obsahuje kromě startovacího souborového systému také aktualizaci mikrokódu. Tu kexec provést neumí.

Závěrem se hodí také napsat, že samozřejmě všechny ty procesy, které se v počítači dějí během POSTu, nejsou úplně samoúčelné; občasný reset může pomoci vrátit celý počítač do jasně definovaného výchozího stavu, což kexec nedokáže. Jako každý nástroj je tedy potřeba používat jej s citem ke konkrétnímu účelu, tedy například rychlé výměně jádra s minimálním výpadkem služeb.

Autor článku

Ondřej Caletka vystudoval obor Telekomunikační technika na ČVUT a dnes pracuje ve vzdělávacím oddělení RIPE NCC, mezinárodní asociaci koordinující internetové sítě.