
Ú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.serviceTento 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.targetA nakonec příklad vykonávaného skriptu:
#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answerNejdů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:
- Spouští se zaváděč
- Zaváděč začíná spouštět firmware a předává parametr final.target
- 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 ( )
- Systém se spouští
- 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ý)
- Spouští se postgresq
- 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)
- Změní se výzva — objeví se fráze Ready to work
- 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.targetJak 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.targetZde 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=300Vš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.targetCo 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/
$commandNapomena. 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\/systemctlStoga ih možete zameniti svojim skriptima:
reboot
#!/bin/sh
touch /tmp/reboot
sudo systemctl isolate my_shutdown.target
fiZdroj: habr.com
