Služba je to, co klasicky známe pod pojmem démon z sysvinit. Jejím úkolem je obsluhovat nějaký skript či program. Proto především definuje, co se má spouštět, jak démona zastavit, či jakého je démon typu (jestli provádí fork, popř. běží jen v jednom hlavním procesu).
Sekce [Service]
Spouštění příkazů
Veškerá konfigurace se provádí v sekci [Service]
. Nejprve je nutné specifikovat, co a kdy se má spouštět. K tomu slouží parametry začínající Exec. Tato pole obsahují příkazy s vlastním definovaným formátem. Pozor, není to shell. Podobně jako konfigurační soubory je to formát, který systemd sám načítá a spouští. Syntaxe je inspirovaná shellem.
Proměnná $PATH zde neexistuje a je tedy nutné zadat celou cestu k příkazům (místo echo
napíšeme /usr/bin/echo
). Před příkazem může být pomlčka, která zajistí, že nenulový návratový kód není považován za chybu. Parametr může obsahovat více příkazů oddělených středníkem. Středník musí být z obou stran oddělený mezerami. Parametry se parsují podobně jako v shellu – jsou odděleny mezerami, speciální znaky jsou escapování zpětným lomítkem a ignorovány v uvozovkách či apostrofech. Víceřádkový parametr je možné vytvořit tak, že na každou řádku kromě poslední přidáme nakonec zpětné lomítko. Není ale možné používat přesměrování (<,<<,>>,>), roury (|) ani pouštění procesů na pozadí (&).
Dále jsou podporovány identifikátory používané v šablonách zmíněné v minulém článku. Také je možné použít proměnné prostředí podobně jako v shellu. Základní použití je $PROMĚNNÁ
. Další varianty je možné najít v man systemd.service
sekce COMMAND LINES.
Pokud z nějakého důvodu potřebujeme shell, můžeme samozřejmě použít příkaz /bin/sh -c "příkaz"
. Následuje tabulka všech parametrů používaných pro spuštění příkazů:
- ExecStart
- Toto je příkaz, který bude spuštěn při startu jednotky. Zde může být maximálně jeden příkaz, který bude považován za hlavní proces. Výjimky viz níže.
- ExecStartPre
- Pomocné příkazy spouštěné po spuštění/před spuštěním hlavního příkazu, může jich být více. V případě, že kterýkoliv z těchto příkazů selže a není uvozený pomlčkou, spouštění je okamžitě zastaveno a hlavní proces nemusí být vůbec spuštěn.
- ExecStartPost
- Analogie ExecStartPre. ExecStartPost je spouštěn až ve chvíli, kdy je služba považována za nastartovanou, co přesně to znamená, si povíme níže.
- ExecReload
- Příkaz, který se má spustit v případě načítání nové konfigurace (spuštění
systemctl reload jednotka
) - ExecStop
- Slouží pro zastavení jednotky, po proběhnutí jsou zbývající procesy ukončeny signálem SIGKILL. Pokud tedy nepotřebujeme nějaké speciální ukončování, není nutné tuto položku specifikovat.
- ExecStopPost
- Příkaz spuštěný vždy po skončení běhu služby, i v případě neočekávaného ukončení služby. Vhodné pro vyčištění pomocných souborů či na půl spuštěné inicializace.
Typy služeb
Služby se ještě rozdělují do několika typů podle spouštění démonů. Typ se definuje parametrem Type
. Více viz tabulka:
- simple
- Výchozí typ. Očekává se, že hlavní proces je příkaz v ExecStart. Také je nutné, aby sockety (pokud nějaké má) byly již spuštěny, protože systemd okamžitě začne startovat další jednotky. Jednotka je považovaná za nastartovanou ve chvíli, kdy byl spuštěn hlavní proces.
- dbus
- Podobné typu simple. Navíc ale musí být specifikováno pole BusName, což je adresa, přes kterou komunikují ostatní procesy s touto službou. Jednotka je považována za nastartovaou, poté co je zaregistrováno poslouchání na dané adrese. Tedy až v tuto chvíli se začnou spouštět jednotky na této závislé a příkaz v ExecStartPost. Také je automaticky nastavena závislost na dbus.
- oneshot
- Podobné typu simple. Jen je služba považována za nastartovanou ve chvíli, kdy proces spuštěný ExecStart skončil. Toto je jediný typ, který může obsahovat více příkazů v ExecStart.
- notify
- Opět podobný typu simple. Očekává se, že pošle signál přes tzv. systemd system notifikací (viz
man sd_notify
), až bude nastartovaná. - forking
- Systemd očekává chování standradních UNIX-ových démonů. Tedy spuštěný proces zavolá
fork()
a ukončí se. Hlavní proces je pak syn tohoto procesu. Jednotka je nastartovaná ve chvíli, kdy je ukončen proces puštěný ExecStart. - idle
- Tato jednotka je spuštěna až ve chvíli, kdy jsou všechny ostatní transakce vyřízeny. V podstatě se používá pouze pro potlačení výstupu služeb na výstup přihlašovací konsole.
Další možnosti konfigurace
Pro typ služby oneshot může být užitečné nastavit parametr RemainAfterExit=yes
, kdy jednotka bude považována za aktivní i po skončení hlavního procesu.
Naopak parametr PIDFile
, který očekává absolutní cestu, může být užitečný pro typ forking. Tento soubor slouží k označení hlavního procesu a navíc bude automaticky odstraněn po skončení jednotky. Pokud si tedy potřebujeme někde udržovat PID soubor, nemusíme se starat o jeho vymazání, ať už při očekávaném či neočekávaném ukončení.
Další zajímavou možností konfigurace je nastavení časových limitů. Je možné nastavit časovbý limit spouštění a vypínaní služby. Výchozí časy jsou 90 vteřin, je možné přes hodnoty DefaultTimeoutStartSec
a DefaultTimeoutStopSec
přenastavit výchozí časy, nebo pro každou jednotku zvlášť pomocí TimeoutStartSec
a TimeoutStopSec
.
Poslední volbou, kterou si ukážeme, je možnost řídit restartování. Položka Restart
může mít několik voleb, více viz tabulka:
- no
- K restartu nedojde nikdy – výchozí varianta.
- on-success
- Jednotka bude restartována, pouze pokud skončí úspěchem.
- on-failure
- Restart jen při selhání.
- on-abnormal
- Restart bude proveden, pokud je jednotka ukončena nějakým signálem (jako např. SIGSEV, ale vyjma SIGHUP, SIGINT, SIGTERM a SIGPIPE), startuje déle než je povolený interval, nebo se po zadaný interval neohlásila (pokud je nastavena volba WatchDog)
- on-abort
- K restartu dojde, pokud je ukončena signálem jako v případě výše.
- on-watchdog
- Restart proběhne, pokud se jednotka neohlásila „hlídacímu psovi“. Pokud nastavíme volbu WatchDogSec, musí se služba pravidelně hlásit pomocí systému notifikací zprávou WATCHDOG=1 v intervalech menších než je udaný interval. (více opět v manuálových stránkách.)
Příklady
Ukážeme si dva jednoduché příklady, které se mohou hodit v praxi. Prvním je smazání nějakých dočasných souborů. Použijeme typ oneshot, protože cílem je jen něco provést a skončit. Nemusíme se bát, že by to brzdilo start počítače, protože, jak jsme si již řekli, start probíhá paralelně. Navíc se po nastartování stane neaktivní, a proto můžeme službu pustit ihned znovu. Řádek SuccesExitStatus=1
zajistí, že pokud jsou v adresáři nesmazatelné soubory (kupříkladu právě otevřené), služba je i tak považována za úspěšně provedenou. Zde samozřejmě již záleží na konkrétních požadavcích administrátora.
[Unit] Description=Vymazání nepotřebných dat. [Service] Type=oneshot ExecStart=/usr/bin/bash -c "rm -rf /tmp/*" SuccessExitStatus=1 [Install] WantedBy=multi-user.target
Další příklad bude na ukázku případu, kdy nechceme spouštět některý příkaz vícekrát. Představme si, že máme vlastní jednoduchý firewall, který chceme ovládat. Opět si vytvoříme službu typu oneshot. Oproti předchozímu příkladu přidáme řádku RemainAfterExit=yes
, díky čemuž bude jednotka po dokončení příkazu v ExecStart
stále aktivní. Pokud bychom aktivovali jednotku znovu, nic se nestane, příkaz pro nastartování znovu pouštěn nebude. Naopak, příkaz vypnutí se zavolá pouze tehdy, když jednotka běží a použijeme systemctl stop. Samozřejmě se jedná jen o ilustrativní příklad, pokud by firewall z nějakého důvodu spadnul, naše jednotka to nepozná.
[Unit] Description=Simple firewall [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/local/sbin/simple-firewall-start ExecStop=/usr/local/sbin/simple-firewall-stop [Install] WantedBy=multi-user.target
Systemd se snaží zachovávat alespoň částečnou zpětnou kompatibilitu se Sysv, proto při startu prochází SysV init skripty (tedy v adresáři /etc/init.d
) a vytváří z nich virtuální služby. Virtuálním v tomto případě myslím, že s ní můžeme standardně pracovat, ale že se pro ni při startu počítače vytvoří speciální konfigurační soubor v /run
(Tento adresář je standardně tmpfs a tedy se jeho obsah po vypnutí ztratí.). Tento převod není stoprocentně kompatibilní. Více na wiki freedesktop.org.
V dnešním dílu jsme si vysvětlili konfiguraci služeb. Příště se podíváme na cíle – ekvivalenty běhových úrovní.