Portál AbcLinuxu, 9. května 2024 12:46

Systemd – .service jednotky, náhrada init skriptů

21. 7. 2011 | Michal Vyskočil
Články - Systemd – .service jednotky, náhrada init skriptů  

V dnešním díle se zaměříme na .service jednotky, což jsou jednotky spouštějící démony, čili přímá náhrada za init skripty. Systemd je nejnovější hvězda v tak poklidné a konzervativní oblasti, jako jsou init systémy. V této sérii článků si probereme jeho vlastnosti.

Obsah

Jednotka .service

Jednotka .service je jednotka sloužící ke spouštění, ukončování a kontrole bežících procesů. Tolik oficiální dokumentace.

Každý typ jednotky má svoji stejnojmennou sekci, takže volby tohoto typu jsou v sekci [Service]. Ve výchozím stavu má každá jednotka implicitní závislosti After=basic.target a Requires=basic.target a Conflicts=shutdown.target a Before=shutdown.target. Těm, kteří se prokousali minulými díly, není třeba vysvětlovat více, pro ostatní – vše podstatné, včetně toho, jak tyto implicitní závislosti potlačit naleznete tam.

Mimo nativních jednotek systemd podporuje rovněž klasické skripty v /etc/init.d, dokonce včetně LSB hlaviček. Právě tato vlastnost usnadňuje přechod z klasického sysvinit rozložení na systemd.

Píšeme .service jednotky

Přepis init skriptu na .service jednotku je poměrně snadný a přímočarý úkol. A výsledek je čitelnější než init skript, který je obvykle plný výplňového kódu. Ten byl přesunut do samotného systemd.

Toto je příklad /etc/init.d/bluetoothd (známým občas pod jménem bluez). Pomineme skutečnost, že přinejmenším Fedora a openSUSE bluetooth démona spouštějí prostřednictvím systému udev.

[Unit]
Description=Bluetooth Daemon
Names=bluez.service
After=syslog.target

[Service]
Type=forking
ExecStart=/usr/sbin/bluetoothd
PIDFile=/var/run/bluetooth.pid

[Install]
Alias=bluez.service
WantedBy=bluetooth.target

Z několika desítek řádků init skriptu pro bluetooth démona jsme se dostali na 11 řádků .service jednotky. Navíc rozdělení jednotlivých voleb do sekcí dále zjednodušuje orientaci – potřebujeme se podívat na to, jakým způsobem jednotka startuje? Prostě se podíváme pouze na sekci [Service] a zbytek ignorujeme.

Volba Description= je popis jednotky. Sekce Names= určuje alternativní názvy pro jednotku a zaručuje, že příkaz systemclt bluez.service bude rovněž fungovat. Volba After=syslog.target zajišťuje, že bude tato jednotka spuštěna až po spuštění systémového logu. Ovšem protože volba After= znamená pouze pořadí a neříká nic o závislostech, neznamená to, že spuštění této služby spustí i syslog. Volba After= znamená, že pokud bude existovat požadavek na spuštění syslog.target a bluetooth.service, bude prvně jmenovaná spuštěna dříve.

Sekce označená jako [Install] říká, že bluez.service je alternativní název pro instalaci této služby. Obvykle je dobré mít obsah [Unit]/Names= a [Install]/Alias= stejný, protože by rozdíly mezi instalačními a názvy za běhu mohly být matoucí. Volba WantedBy= říká, že tato jednotka bude vyžadována jednotkou bluetooth.target, čili při instalaci bude vytvořen symbolický odkaz v bluetooth.target.wants.

Prostřední sekcí [Service] se bude zabývat následující text.

Typy služeb

link

Nejdůležitějším parametrem je Type=, čili typ služby, kterou hodláme spouštět. Systemd rozeznává 5 rozličných typů – simple, forking, oneshot, dbus a notify.

Výchozí hodnota simple říká, že proces definovaný v ExecStart= bude hlavním procesem služby. V tomto režimu musí být komunikační kanály nastaveny před vlastním spuštěním procesu. Tato volba je vlastní například /sbin/sulogin v emergency.target a systemd spouští závislé jednotky okamžitě.

Typ oneshot je podobný typu simple s tím rozdílem, že systemd spustí závislou jednotku až poté, co daný proces doběhne. Toto je klasický typ různých služeb běžících při startu a ukončování systému jako například fsck@.service, clock.service (odstraněna v systemd-28) nebo quotaon.service. Posledně jmenovaná má navíc nastaven parametr RemainAfterExit=yes, což znamená, že služba quotaon.service, jinak jednorázové spuštění příkazu /sbin/quotaon, bude i po ukončení běhu procesu považována za aktivní. Jinak by start každé závislé jednotky na quotaon.service vyvolal spuštění tohoto příkazu.

Dalším typem je dbus, což opět obdoba typu simple, ovšem zde se očekává, že démon nakonec zabere svoje jméno na D-BUS sběrnici tak, jak určuje parametr BusName=. Systemd spustí závislé jednotky až poté, co dojde k onomu zabrání jména. Tyto jednotky získávají implicitní závislost na dbus.target.

Nastavení forking je pro tradiční unixové démony, které volají fork(2). Rodičovský proces skončí okamžikem, kdy se dokončí démonizace a nastavení komunikačních kanálů. Démonizovaný proces potom běží dál samostatně. Pro forking démony je vhodné uvést umístění souboru s číslem procesu parametrem PIDFile=. Další procesy jsou nastartovány až poté, so skončí rodičovský proces. Typickým představitelem tohoto typu je acpid.

Typ notify očekává aktivní notifikaci stavu spuštěného démona, k čemuž slouží volání sd_notify(3) (o sd_funkcích se dozvíme v následujících částech), nebo podobné volání. V tomto případě systemd spouští závislé služby až potom, co byl démonem upozorněn, že dokončil svůj start. Tato volba je určena pro démony, které z nějakých důvodů nemohou svůj start notifikovat jinak, třeba připojením se na sběrnici D-BUS. Představitelem je udev.service.

NotifyAccess= pak specifikuje přístup k notifikačnímu socketu, kterým proces komunikuje se systemd (viz sd_notify(3)). Možnosti jsou none – žádné zprávy nejsou akceptovány, main – pouze ty od hlavního procesu nebo all – všechny zprávy dané kontrolní skupiny jsou akceptovány. Tato volba má smysl, pokud notifikaci provádíme příkazem /bin/systemd-notify.

Lepší jednotka bluetooth.service

Přepis jednotek jedna k jedné je sice snadný a možný, ale nikterak nevyužívá schopností systemd, mezi něž patří především spouštění na požádání. Démon bluetoothd používá ke komunikaci sběrnici D-BUS, čili v tomto případě je lepší použít typ dbus.

Relevantní část se změní na 

[Service]
Type=dbus
BusName=org.bluez
ExecStart=/usr/sbin/bluetoothd -n

čili démon bluetoothd bude spuštěn v případě, že démon dbus obdrží požadavek na nějakou službu z org.bluez. Připomínám, že dbus démon byl upraven tak, aby dokázal požadavky na spuštění služeb přesměrovat na systemd. To znamená, že služby aktivované přes D-BUS jsou spuštěné stejným způsobem a mají k dispozici stejné nastavení, jako ty ostatní.

Spouštění služeb

link

ExecStart= určuje příkazový řádek, který má být vykonán pro start této jednotky, a je povinný. První část argumentu musí být absolutní cesta k příkazu (sbohem špatně nastavené PATH=), následovaná argumenty pro tento příkaz. Výše uvedená clock.serviceExecStart=/sbin/hwclock --systz. Respektive měla, protože od verze systemd 28 byla tato jednotka zrušena.

Tato volba nesmí být uvedena více než jednou – s výjimkou typu oneshot. V tomto případě jsou příkazy spouštěny postupně v pořadí, ve kterém jsou uvedeny v souboru.

V případě, že absolutní cesta začíná na @, bude první část vynechána ze seznamu argumentů daného programu, což znamená, že hodnota argv[0], která označuje název programu, bude rovna druhému argumentu. Takže program spuštěný s ExecStart=@/usr/bin/foo bar bude mít v argv hodnotu bar.

Pokud je prvním prefixem znak -, je ignorován návratový kód služby, takže je spuštění považováno vždy za úspěšné. Příkladem je ExecPrefix=-/bin/sulogin z emerency.target. Pokud je potřeba oba znaky zkombinovat, potom musí být ve tvaru -@.

S výjimkou typu forking je vždy proces nastartovaný příkazem za ExecStart považován za hlavní proces démona. V praxi to znamená, pokud spouštíme službu pomocí nějakého shellového wrapperu, musíme démona spouštět pomocí exec. V případě typu forking se systemd dívá na pid soubor.

Podporováno je i nahrazování proměnných prostředí, takže ${FOO} bude nahrazenou hodnotou proměnné stejného jména. Stejně tak i $FOO může být uveden jako samostatné slovo na příkazové řádce a v tom případě je nahrazeno hodnotou rozdělenou bílými znaky. Ovšem jméno příkazu musí být stále absolutní cesta k binárnímu souboru.

Ukončení služby

link

ExecStop= jsou příkazy spouštěné pro zastavení služby. Podporuje ${MAINPID} jako ExecReaload= a všechny ostatní vlastnosti uvedené výše. Narozdíl od sysvinit skriptů je tato volba čistě volitelná a případné zbývající procesy jsou ukončeny podle volby KillMode=.

ExecStopPost= jsou příkazy spuštěné po ExecStop= – využití je mizivé, ovšem rescue.serviceExecPostStop=/bin/systemctl default.

Stejně jako se rozeznává několik typů procesů pro spouštění, existuje i několik různých typů z hlediska vypínání. Ty určuje volba KillMode=, jejíž argumenty jsou control-group, process-group, process, nebo none.

Argument control-group značí, že systemd po skončení příkazu ExecPost= ukončí všechny zbývající procesy patřící do stejné kontrolní skupiny (cgroup) jako hlavní proces. Volba process-group značí, že budou ukončeny procesy patřící do stejné skupiny procesů. Možnost process znamená, že se má ukončit pouze hlavní proces, a volba none potlačí jakékoli vypínání procesů, takže bude proveden pouze příkaz uvedený v ExecStop=.

Schéma vypínání je následující: Nejprve je zaslán SIGTERM (lze předefinovat volbou KillSignal=). Pokud po době specifikované parametrem TimeoutSec= jsou procesy stále naživu, je jim zaslán SIGKILL. Výchozí hodnota je 60.

Další možností je použít argument -s příkazu systemctl kill, takže

# systemctl kill -s SIGKILL bluetoothd.service

Pošle procesům SIGKILL. Dalším parametrem můžete omezit počet procesů, kterým se signál posílá, takže požadavek na znovunahrání konfigurace je

# systemctl kill -s SIGHUP --kill-who=ḿain bluetoothd.service

Ostatní volby typu Exec

ExecStartPre= a ExecStartPost= jsou příkazy spouštěné před, případně po příkazu ExecStart=. Příkazy mohou být odděleny středníkem, nebo může být uvedeno více voleb po sobě, i když druhá forma může být nekompatibilní s nastroji očekávající XDG .desktop formát. Podporovány jsou všechny vlastnosti zmíněné u ExecStart=.

Příkladem použití je rescue.service:

    ExecStartPre=-/bin/plymouth --hide-splash
    ExecStartPre=-/bin/echo 'Welcome to rescue mode. Use „systemctl default“ or
    ^D to activate default mode.'
    ExecStart=-/sbin/sulogin

Volba ExecReload= určuje způsob, jímž se službě říká, aby znovu načetla konfiguraci. Jejím argumentem může být rovněž více příkazů jako u ExecStartPre/Post. Podporována je proměnná ${MAINPID}. ExecReload= pak obvykle vypadá jako /bin/kill -HUP ${MAINPID}, ale různé služby lze požádat různě. Například dbus.service vypadá takto:

ExecStartPre=/bin/dbus-uuidgen --ensure
ExecStartPre=-/bin/rm -f /var/run/dbus/pid
ExecStart=/bin/dbus-daemon --system --address=systemd: --nofork \
--systemd-activation
ExecReload=/bin/dbus-send --print-reply --system --type=method_call \
--dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig

Restart

link

Restart= určuje, zda má být hlavní proces služby restartován, pokud skončí, nebo ne. Výchozí hodnotou je no, čili služba nebude restartována. Při on-success bude restartována pouze v případě, že skončila s návratovým kódem 0 a při always bude restartována vždy, bez ohledu na návratovou hodnotu. Protože je poslední možnost alternativou k respawn u klasického initu, není překvapením, že je tato volba přítomná u getty@.service.

RestartSec= je interval mezi ukončením a opětovným spuštěním služby. Výchozí hodnota je 100ms. U getty@.service je nastavena na 0.

Závěrem

link

Tento díl nakousl praktičtější část problematiky systemd, totiž .service jednotky. Dozvěděli jsme se, které typy démonů systemd nativně podporuje, jak spustit, zastavit, nebo požádat o znovunahrání konfigurace. Příští díl se bude věnovat kontrole prostředí, v němž bude proces spuštěn.

Seriál Systemd (dílů: 7)

První díl: Systemd – úvod a představení System V init, poslední díl: Systemd – .service jednotky, náhrada init skriptů.
Předchozí díl: Systemd – psaní unixových démonů

Odkazy a zdroje

systemd.service
How Do I Convert A SysV Init Script Into A systemd Service File
Killing Services
Three levels of off

Další články z této rubriky

Úvod do Dockeru (1)
Paralelizace běžných činností v konzoli pomocí GNU Parallel
Unixové nástroje – 26 (triky pro práci v Bashi)
Unixové nástroje – 25 ((s,c)fdisk, gdisk, parted a findmnt)
Linux: systémové volání splice()

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.