Systemd, interaktivní skripty a časovače

Systemd, interaktivní skripty a časovače

Úvod

Při vývoji pod linuxem se objevují úkoly vytváření interaktivních skriptů, které se provádějí při zapnutí nebo vypnutí systému. U system V to bylo snadné, ale s systemd došlo ke změnám. Na druhou stranu má své časovače.

K čemu jsou targety

Často se píše, že targety slouží jako ekvivalent runlevel v system V -init. S tím však zásadně nesouhlasím. Je jich více a lze rozdělit balíčky do skupin a třeba jedním příkazem spustit skupinu služeb a provést další akce. Navíc nemají hierarchii, pouze závislosti.

Příklad targetu při zapnutí (přehled funkcionality) spouštějícího interaktivní skript

Popis samotného targetu:

cat installer.target
[Unit]
Description=Můj instalátor
Requires=multi-user.target 
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target 
AllowIsolate=yes
Wants=installer.service

Tento target se spustí, když se spustí multi-user.target a vyvolá installer.service. Může jich být víc.

cat installer.service
[Unit]
# popis
Description=interaktivní dialog instalátoru

[Service]
# Spustit jednou, když bude ostatní spuštěno
Type=idle
# Příkaz pro spuštění - volání skriptu
ExecStart=\/usr\/bin\/installer.sh
# Interaktivní komunikace s uživatelským prostřednictvím tty3
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes

[Install]
WantedBy=installer.target

A nakonec příklad vykonávaného skriptu:

#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answer

Nejdůležitější je vybrat final.target - target, kterého má systém dosáhnout při spuštění. Během spuštění systemd projde závislostmi a spustí vše potřebné.
Výběr final.target lze provést různými způsoby, já jsem k tomu použil možnost zaváděcího programu.

Konečné spuštění vypadá takto:

  1. Spouští se zaváděč
  2. Zaváděč začíná spouštět firmware a předává parametr final.target
  3. Systemd začíná spouštět systém. Postupně se dostává k installer.target nebo work.target z basic.target skrze jejich závislosti (například multi-user.target). Tyto poslední nakonec přivedou systém do požadovaného režimu.

Příprava firmware na spuštění

Při vytváření firmwaru se vždy objevuje úkol obnovit stav systému při spuštění a jeho uložení při vypnutí. Stav zahrnuje konfigurační soubory, dumpy databází, nastavení rozhraní atd.

Systemd spouští procesy v jednom targetu paralelně. Existují závislosti, které určují pořadí spuštění skriptů.

Jak to funguje u mě v projektu ( https://habr.com/ru/post/477008/ https://github.com/skif-web/monitor)

  1. Systém se spouští
  2. Spouští se služba settings_restore.service. Kontroluje se přítomnost souboru settings.txt v datovém oddílu. Pokud chybí, nahrazuje se standardním souborem. Následně dochází k obnovení systémových nastavení:
    • administrátorského hesla
    • hostname,
    • časového pásma
    • lokality
    • Určení, zda je celá média využita. Výchozí velikost obrazu je malá — pro usnadnění kopírování a zápisu na médium. Při spuštění se kontroluje, zda je ještě nějaké nevyužité místo. Pokud ano, disk se znovu rozděluje.
    • Generování machine-id z MAC adresy. To je důležité pro získání stejné adresy přes DHCP
    • Nastavení sítě
    • Omezení velikosti logů
    • Připravuje se vnější disk (pokud je povolena příslušná volba a disk je nový)
  3. Spouští se postgresq
  4. spouští se služba restore. Ta je potřebná pro přípravu samotného zabbixu a jeho databáze:
    • Kontroluje se, zda již existuje databáze zabbix. Pokud ne, vytváří se z inicializačních dumpů (dodáváno se zabbixem)
    • vytváří se seznam časových pásem (potřebný pro zobrazení v webovém rozhraní)
    • Zjistí se aktuální IP, ta se zobrazuje v příkazu (výzva pro přihlášení do konzole)
  5. Změní se výzva — objeví se fráze Ready to work
  6. Firmware je připraven k práci

Jsou důležité soubory služeb, právě ty určují pořadí jejich spuštění

[Unit]
Description=obnovit systémová nastavení
Before=network.service prepare.service postgresql.service systemd-networkd.service systemd-resolved.service

[Service]
Type=oneshot
ExecStart=/usr/bin/settings_restore.sh

[Install]
WantedBy=multi-user.target

Jak je vidět, nastavil jsem závislosti, aby nejprve běžel můj skript a teprve poté byla spuštěna síť a databázový systém.

A druhá služba (příprava zabbixu)

#!/bin/sh
[Unit]
Description=monitor prepare system
After=postgresql.service settings_restore.service
Before=zabbix-server.service zabbix-agent.service

[Service]
Type=oneshot
ExecStart=/usr/bin/prepare.sh

[Install]
WantedBy=multi-user.target

Zde je to o něco složitější. Spouští se také v multi-user.target, ale PO spuštění databázového systému postgresql a mého setting_restore. Ale PŘED spuštěním služeb zabbix.

Služba s časovačem pro logrotate

Systemd může nahradit CRON. Opravu. Přičemž přesnost není do minuty, ale do sekundy (co kdyby to bylo potřeba). A také je možné vytvořit monotónní časovač, který se volá podle časového intervalu od události.
Vytvořil jsem právě monotónní časovač, který počítá čas od spuštění stroje.
K tomu jsou zapotřebí 2 soubory
logrotateTimer.service — popis služby:

[Unit]
Description=spustit logrotate

[Service]
ExecStart=logrotate /etc/logrotate.conf
TimeoutSec=300

Vše je jednoduché — popis příkazu spuštění.
Druhý soubor logrotateTimer.timer — ten určuje provoz časovačů:

[Unit]
Description=Spustit logrotate

[Timer]
OnBootSec=15min
OnUnitActiveSec=15min

[Install]
WantedBy=timers.target

Co zde máme:

  • popis časovače
  • Čas prvog pokretanja, počevši od učitavanja sistema
  • period daljih pokretanja
  • Zavisnost od servisnih časova. U suštini, to je niz i pravi časovnik

Interaktivni skript prilikom isključivanja i njegov ciljani isključak

U drugom razvoju, morao sam napraviti složeniju verziju isključivanja mašine — preko vlastitog cilja, kako bih izvršio niz radnji. Obično se preporučuje kreiranje servisa oneshot sa opcijom RemainAfterExit, ali to ne omogućava kreiranje interaktivnog skripta.

A stvar je u tome što se komande, koje se pokreću opcijom ExecOnStop, izvršavaju van TTY-a! Proveriti je jednostavno — ubacite komandu tty i sačuvajte njen izlaz.

Zato sam realizovao isključivanje preko svog cilja. Na 100% tačnost ne računam, ali funkcioniše!
Kako je to rađeno (u opštem smislu):
Kreirao sam cilj my_shutdown.target, koji nije zavisio od drugih:
my_shutdown.target

[Unit]
Description=můj shutdown
AllowIsolate=yes
Wants=my_shutdown.service 

Prilikom prelaska u ovaj cilj (putem systemctl isolate my_shutdown.target), pokrenuo je servis my_shutdown.service, čija je zadatak jednostavna — izvršiti skript my_shutdown.sh:

[Unit]
Description=MY shutdown

[Service]
Type=oneshot
ExecStart=\/usr\/bin\/my_shutdown.sh
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes

WantedBy=my_shutdown.target

  • Unutar ovog skripta izvršavam potrebne radnje. U cilj se može dodati više skripti, radi fleksibilnosti i udobnosti:

my_shutdown.sh

#!/bin/bash --login
if [ -f /tmp/reboot ];then
    command="systemctl reboot"
elif [ -f /tmp/shutdown ]; then
    command="systemctl poweroff"
fi
#Вот здесь нужные команды
#Например, cp /home/user/data.txt /storage/user/
    $command

Napomena. Korišćenje datoteka \/tmp\reboot i \/tmp\shutdown. Ne može se pozvati cilj sa parametrom. Može se samo servis.

Ali ja koristim cilj, kako bih imao fleksibilnost u radu i garantovan redosled izvršavanja radnji.

Međutim, najzanimljivije je bilo kasnije. Mašinu treba isključiti\/ponovo pokrenuti. I ovde postoje 2 opcije:

  • Zameniti komande reboot, shutdown i druge (one su ionako simbolične veze na systemctl) svojim skriptom. Unutar skripta — prelazak u my_shutdown.target. A skripti unutar cilja zatim pozivaju direktno systemctl, na primer, systemctl reboot.
  • Jednostavnija, ali meni nezadovoljavajuća opcija. U svim interfejsima pozivati ne shutdown\/reboot\/druge, već direktno pozivati cilj systemctl isolate my_shutdown.target.

Izabrao sam prvu opciju. U systemd reboot (kao i poweroff) su simbolične veze na systemd.

ls -l \/sbin\/poweroff 
lrwxrwxrwx 1 root root 14 sep 30 18:23 \/sbin\/poweroff -> \/bin\/systemctl

Stoga ih možete zameniti svojim skriptima:
reboot

#!/bin/sh
    touch /tmp/reboot
    sudo systemctl isolate my_shutdown.target
fi

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster