Nebojte se systemd 6: zbývající typy jednotek

Minule jsme si představili cíle. Dnes se podíváme na všechny zbývající typy jednotek, tj. typy mount, automount, swap, timer, socket, device, slice a scope.

Typ mount

Jednotky typu mount slouží pro správu připojených souborových systémů. Jejich jména odpovídají cestě, kam je souborový systém připojen, kde lomítka jsou nahrazena pomlčkou a první lomítko je vynecháno (kromě /, který se jmenuje -.mount). Domovskou složku proto pojmenujeme  home.mount.

 

I u tohoto typu jsou sekce install a unit stejné. Definujeme v nich tedy např. cestu k dokumentaci či závislosti. Kromě běžných závislostí se ještě nastavují automatické závislosti (required a after/before) dle hierarchie souborového systému. Pokud tedy máme jednotky home.mount a home-knezi.mount, druhá jednotka má automaticky nastaveno:

After=home.mount Required=home.mount

V sekci mount definujeme především What, Where a Type, které určují po řadě, které zařízení chceme připojit, kam se připojuje (toto pole musí odpovídat jménu) a typ souborového systému. Parametrem Option můžeme ještě nastavit přepínače dostupné pro mount -o. Příklad takové jednotky je níže:

[Unit] SourcePath=/etc/fstab Documentation=man:fstab(5) man:systemd-fstab-generator(8) Before=local-fs.target Requires=systemd-fsck@dev-sda7.service After=systemd-fsck@dev-sda7.service  [Mount] What=/dev/sda7 Where=/mnt/home Type=ext4 Options=rw,relatime,data=ordered

Na příkladu také vidíme, že /mnt/home je vytvořen automaticky ze souboru /ect/fstab. K tomuto slouží tzv. generátory, které umožňují vytvářet jednotky dynamicky při startu počítače. Systemd je vytváří ještě před načtením již existujících jednotek, díky čemuž jsou k dispozici velmi brzy po startu počítače a je možno s nimi pracovat jako se standardními jednotkami. S jedním generátorem jsme se již setkali, konkrétně vytváření virtuálních jednotek ze SysV init skriptů je realizováno přesně generátorem.

Dalším generátorem je systemd-fstab-generator, který čte soubor /etc/fstab a generuje z nich jednotky typu mount. Proto není nutné pro každý disk vytvářet novou jednotku, ale stačí mít správně nakonfigurovaný fstab.

Se souborovým systémem jsou spojeny ještě dva další typy. Prvním je automount, který lze použít pro připojování souborových systémů, až když jsou opravdu potřeba. Pokud např. chceme připojit /mnt/disk až při prvním přístupu, vytvoříme jednotku mnt-disk.automount, které opět musíme nastavit parametr Where odpovídající jménu. Navíc musí existovat jednotka mnt-disk.mount, která připojuje daný souborový systém a v případě přístupu do cesty /mnt/disk bude aktivována. Zároveň je také možné nastavit parametrem TimeoutIdleSec, který definuje, za jak dlouho se při nečinnosti mnt-disk.mount deaktivuje a tedy dojde k odpojení souborového systému.

Pro úplnost ještě zmiňme typ swap, který slouží pro definování stránkovacího souboru. Opět funguje dynamické vytváření přímo z fstabu a protože je swap většinou nastaven již při instalaci, málokdy je nutné s tímto typem vůbec pracovat.

typ časovač

Pro spouštění procesů v pravidelných intervalech se dříve používal cron. V systemd pro tuto úlohu existuje typ časovač. Pokud chceme jednotku logrotate.service (více o této službě v některém z následujících dílů seriálu) spouštět pravidelně, vytvoříme časovač logrotate.timer. Princip je podobný jako v případě automount s tím rozdílem, že shoda jmen je doporučena. Můžeme specifikovat pomocí parametru Unit službu, která bude aktivována při uplynutí intervalu časovače.

V sekci Timer se nastaví přesný interval spouštění. Následující parametry určují, za kolik vteřin má být časovač aktivován od:

OnActiveSec
poslední aktivace samotného časovače
OnUnitActiveSec
poslední aktivace služby
OnUnitInactiveSec
poslední deaktivace služby
OnBootSec
nastartování počítače

Vhodnou kombinací OnBootSec a OnActiveSec můžeme zajistit aktivaci za nějakou dobu po startu stroje a další aktivaci v zadaném intervalu. Argumenty jsou ve tvaru definovaném v man systemd.time, jako argument proto stačí jen číslo udávající počet vteřin. Také můžeme použít čísla s příponami (např. 5h 30min).

Další možností je aktivovat časovač v zadaný datum. Můžeme použít formát podobný konfiguraci cronu. Tedy napíšeme datum a ty položky, které chceme, aby se opakovaly, nahradíme hvězdičkou. Kupříkladu *-*-2 12:00:00 odpovídá každému druhému dni v měsíci ve dvanáct hodin. Kromě toho je možné použít hodnoty jako hourly, daily, weekly. Seznam všech je v man systemd.time  sekce calendar events.

[Unit] Description=Daily rotation of log files  [Timer] OnCalendar=daily AccuracySec=12h Persistent=true

V příkladu výše bude jednotka logrotate.service spouštěna každý den. Parametr AccuracySec říká, že jednotka se může spustit kdykoliv během dvanácti hodin kolem požadovaného intervalu (tedy to říká, že není důležité, kdy přesně se spustí). Persistent určuje, že pokud by se časovač během doby vypnutí počítače alespoň jednou měl spustit, bude spuštěn okamžitě při startu.

typ path

Typ path slouží k monitorování souborového systému. Tato jednotka bude aktivována, nastane-li nějaká akce, např. složka přestane být prázdná, či nějaký soubor bude vytvořen. V našem příkladu kdykoliv se ve složce /home/knezi/in objeví nějaký soubor, bude přesunut do /tmp, protože parametr DirectoryNotEmpty zajistí, že kdykoliv je složka neprázdná, bude aktivována jednotka  move2tmp.service.

home-knezi-in.service

[Path] DirectoryNotEmpty=/home/knezi/in Unit=move2tmp.service

move2tmp.service

[Service] Type=Oneshot ExecStart=/bin/sh -c "mv /home/knezi/in/* /tmp"

Další užitečné možnosti jsou PathExists (cesta existuje, jednotka je spuštěna ve chvíli, kdy je vytvořen příslušný soubor nebo složka). PathExistGlob navíc testuje existenci libovolného souboru definovaného expanzním výrazem (angl. glob pattern) – tedy je možno použít hvězdičku či hranaté závorky. Je vhodné poznamenat, že typ path je realizovaný pomocí inotify a trpí tak stejnými neduhy, např. není možné monitorovat NFS.

Typ socket

Socket obecně slouží ke zprostředkování komunikace mezi procesy. Ta může být realizována pomocí posílání paketů, kdy každý proces dostane svůj port, nebo speciálním FIFO souborem, který se chová jako fronta. Tedy do něj procesy zapisují data a proces, kterému tento soubor patří, z něj čte ve stejném pořadí, v jakém byla data zapsána. Systemd pro tento mechanismus zavádí další typ jednotky – socket. Ten kromě jiného umožňuje spouštění obslužného procesu až ve chvíli, kdy je potřeba.

Ukažme si modelový příklad. Budeme chtít, aby služba move2tmp.service přijímala data a zapisovala je postupně do souboru /tmp/tmp. K tomu slouží následující kód, který si hned vysvětlíme:

move2tmp.c

#include "systemd/sd-daemon.h" #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <string.h>  int main(int argc, char **argv) {     int socket = SD_LISTEN_FDS_START + 0;      int fd=open("/tmp/tmp", O_WRONLY|O_APPEND);     char buf[128];     while(read(socket, buf, 127)!=-1) {         write(fd, buf, strlen(buf));     }      close(fd);     close(socket);      return 0; }

move2tmp.service

[Service] ExecStart=/home/knezi/.localbin/move2tmp.bin

move2tmp.socket

[Socket] ListenFIFO=/tmp/socket

Pokud spustíme příkazy systemctl start move2tmp.service a poté echo Funguji my sockety > /tmp/socket, v souboru /tmp/tmp se objeví námi zapsaný text.

Ve chvíli, kdy aktivujeme jednotku move2tmp.socket, vytvoří se speciální soubor /tmp/socket, který bude naším socketem. O aktivaci služby move2tmp.service se nestaráme – aktivuje se sama, až bude potřeba. Po jejím skončení dojde k deaktivaci. Díky tomu služba opravdu běží, jen když něco dělá.

V momentě, kdy zapíšeme do /tmp/socket, aktivuje se move2tmp.service, která ihned spustí zkompilovanou binárku move2tmp.c. Protože je služba aktivovaná socketem, systemd zároveň spuštěnému procesu předá adresu na pole file deskriptorů všech socketů, které jsou k dispozici. Pak již jen přečteme data a připíšeme je na konec souboru.

Příklad je samozřejmě trochu umělý a slouží spíše pro demostraci. Reálně by se musely ošetřit ještě chyby. Zároveň také tiše předpokládáme, že dostaneme právě jeden socket. Pro skutečný počet předaných socketů můžeme použít funkci sd_listen_fds.

Co se týče konfigurace socketu, opět platí konvence o stejném jméně. Spouštěnou službu je však možné změnit parametrem Service. Parametr ListenFIFO říká, že chceme vytvořit socket jako soubor a zároveň určuje cestu k tomuto souboru. Pokud bychom chtěli poslouchat na daném portu, můžeme použít parametr ListenStream. Pro přesnější detaily si dovolím čtenáře odkázat do man systemd.socket. Ještě si všimněme, že jméno socketu není nikde v kódu obsluhy, pokud jej budeme chtít změnit, stačí změnit jednu řádku konfigurace socketu.

Typy device, slice, scope

Typ device reprezentuje některá zařízení. Automaticky se vytvářejí ty, které mají v udev nastavený tag systemd. Tento typ nemá žádnou sekci device, a proto se nejčastěji používá pro definici závislostí.

Typ slice je určen pro hierarchické omezování zdrojů počítače. Tomuto nastavíme omezení (např. na velikost alokované RAM) a poté určíme, které služby budou spouštěny v této skupině. Všechny spuštěné dohromady se pak musí dělit o stanovené prostředky. Pokud budeme mít jednotky user.slice a user-knezi.slice, tak jednotka user-knezi.slice (a tedy dohromady všechny v ní spuštěné) sdílí prostředky s ostatními, které jsou spuštěny v  user.slice.

S typem slice souvisí scope, který je vytvářen pouze programově za běhu. Slouží ke slučování již běžících procesů, které nejsou spravovány žádnou jednotkou. Pomocí tohoto je pak možné omezovat jejich systémové zdroje stejně jako u jednotek.

Tím jsme vyčerpali dnešní téma a zároveň probrali všechny typy jednotek. Příště se podíváme na všeobecná nastavení systemd.

Zdroj: https://www.root.cz/clanky/nebojte-se-systemd-zbyvajici-typy-jednotek/