Hlavní navigace

Nebojte se systemd: služby

13. 6. 2016
Doba čtení: 6 minut

Sdílet

 Autor: Shutterstock.com
Minule jsme si představili obecnou strukturu konfiguračních souborů. V dalších částech si budeme postupně představovat jednotlivé typy. Dnes se podíváme na služby (service).

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í TimeoutStartSecTimeoutStopSec.

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á.

CS24_early

[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í.

Byl pro vás článek přínosný?

Autor článku

Autor studuje na Matematicko-fyzikální fakultě. Ve svém volném čase se kromě Linuxu věnuje také vlastní 3D tiskárně.