
Úvod
Pri vývoji pod linuxom sa objavujú úlohy vytvárania interaktívnych skriptov, ktoré sa vykonávajú pri zapnutí alebo vypnutí systému. V system V to bolo jednoduché, ale s systemd to prináša úpravy. Na druhej strane, to má svoje časovače.
Na čo sú potrebné ciele
Často píšu, že ciele slúžia ako ekvivalent runlevel v system V – init. S tým sa zásadne nesúhlasím. Je ich viac a môžete rozdeľovať balíky podľa skupín a napríklad spustiť jednou príkazom skupinu služieb, vykonať ďalšie akcie. Okrem toho nemajú hierarchiu, iba závislosti.
Príklad cieľa pri zapnutí (prehľad možností) so spustením interaktívneho skriptu
Popis samotného cieľa:
cat installer.target
[Unit]
Description=Môj inštalátor
Requires=multi-user.target
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes
Wants=installer.serviceTento cieľ sa spustí, keď bude spustený multi-user.target a vyvolá installer.service. Takýchto služieb môže byť pritom niekoľko.
cat installer.service
[Unit]
# popis
Description=interaktívny dialóg inštalátora
[Service]
# Spustiť raz, keď sa ostatné spustia
Type=idle
# Príkaz na spustenie - vyvolanie skriptu
ExecStart=\/usr\/bin\/installer.sh
# Interaktívna interakcia s užívateľom cez tty3
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes
[Install]
WantedBy=installer.targetA nakoniec, príklad vykonávaného skriptu:
#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answerNajdôležitejšie je vybrať final.target - cieľ, ku ktorému sa systém má pri spustení priblížiť. Počas spúšťania systemd prejde závislosťami a spustí všetko potrebné.
Final.target je možné vybrať rôznymi spôsobmi, ja som na to použil možnosť bootloadera.
Konečné spustenie vyzerá takto:
- Spustí sa bootloader
- Bootloader začína spúšťať firmware, prenášajúc parameter final.target
- Systemd začína spúšťať systém. Postupne prechádza k installer.target alebo work.target od basic.target cez ich závislosti (napríklad multi-user.target). Posledné privádzajú systém do prevádzky v požadovanom režime.
Príprava firmvéru na spustenie
Pri vytváraní firmvérov sa vždy objavuje úloha obnovy stavu systému pri štarte a jeho uchovania pri vypnutí. Pod stavom sa rozumejú konfiguračné súbory, dumpy databáz, nastavenia rozhraní a pod.
Systemd spúšťa procesy v jednom cieli súbežne. Existujú závislosti, ktoré umožňujú určiť poradové spúšťanie skriptov.
Ako to funguje u mňa v projekte ( )
- Systém sa spúšťa
- Služba settings_restore.service sa spustí. Skontroluje prítomnosť súboru settings.txt v sekcii s dátami. Ak tam nie je, nahradí ho referenčným súborom. Následne prebieha obnova nastavení systému:
- admin hesla
- hostname,
- časového pásma
- lokalizácie
- Určenie, či je celý spôsob využívaný. Predvolene je veľkosť obrazu malá — pre pohodlie kopírovania a zápisu na zariadenie. Pri spustení sa kontroluje, či je ešte nevyužité miesto. Ak áno, disk sa znova rozdelí.
- Generovanie machine-id z MAC adresy. To je dôležité pre získanie stálej adresy cez DHCP.
- Nastavenia siete
- Obmedzenie veľkosti logov
- Pripravuje sa externý disk (ak je povolená príslušná možnosť a disk je nový)
- Spustenie postgresq
- služba restore sa spúšťa. Táto služba je potrebná na prípravu samotného zabbixu a jeho databázy:
- Kontroluje sa, či už existuje databáza zabbix. Ak nie, vytvorí sa z inicializačných dumpov (tie sú dodávané s zabbixom)
- vytvorí sa zoznam časových pásiem (dôležité na ich zobrazenie vo webovom rozhraní)
- Nájde sa aktuálny IP, ktorý sa zobrazuje v pozvaní (výzva na prihlásenie do konzoly)
- Pozvánka sa mení — objaví sa fráza Ready to work
- Firmware je pripravené na prácu
Dôležité sú súbory služieb, práve tie určujú poradie ich spustenia
[Unit]
Description=obnovenie systémových 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.targetAko vidno, nastavil som závislosti, aby prvý môj skript bol vykonaný, a až potom sa spustila sieť a databáza.
A druhá služba (prí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.targetTu je to trochu zložitejšie. Spustenie tiež v multi-user.target, ale PO spustení databázy postgresql a môjho setting_restore. Ale PRED spustením služieb zabbix.
Služba s časovačom pre logrotate
Systemd môže nahradiť CRON. Naozaj. Časová presnosť nie je len na minútu, ale na sekundu (pre prípad, že by bola potrebná). Môže sa tiež vytvoriť monotónny časovač, ktorý sa volá na základe timeoutu od udalosti.
Práve monotónny časovač, ktorý meria čas od spustenia stroja, som vytvoril.
Na to budú potrebné 2 súbory
logrotateTimer.service — propriálne popis služby:
[Unit]
Description=spustiť logrotate
[Service]
ExecStart=logrotate \/etc\/logrotate.conf
TimeoutSec=300Je to jednoduché — popis príkazu na spustenie.
Druhý súbor logrotateTimer.timer — ten určuje prácu časovačov:
[Unit]
Description=Spustiť logrotate
[Timer]
OnBootSec=15min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.targetČo je tu:
- Opis časova
- Čas prvog pokretanja, počevši od učitavanja sistema
- Period narednih pokretanja
- Zavisnost od usluge tajmera. U suštini, ovo je linija koja čini tajmer
Interaktivni skript prilikom gašenja i vaša ciljana gašenja
U drugom razvoju morao sam napraviti složeniju verziju gašenja mašine — kroz svoju metu, kako bih izvršio više radnji. Obično se preporučuje da se kreira usluga oneshot sa opcijom RemainAfterExit, ali to ne omogućava kreiranje interaktivnog skripta.
Problem je u tome što se komande pokrenute pomoću opcije ExecOnStop izvršavaju van TTY! Proverite jednostavno — umetnite komandu tty i sačuvajte njen izlaz.
Stoga sam implementirao gašenje kroz svoju metu. Ne tvrdim da je 100% ispravno, ali to funkcioniše!
Kako se to radilo (u opštim crtama):
Kreirao sam metu my_shutdown.target, koja nije zavisila ni od koga:
my_shutdown.target
[Unit]
Description=my shutdown
AllowIsolate=yes
Wants=my_shutdown.service Pri prelasku u ovu metu (kroz systemctl isolate my_shutdown.target), pokrenuo je uslugu my_shutdown.service, čija je zadaća 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. Možete dodati mnogo skripti u metu za fleksibilnost i praktičnost:
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. Nije moguće pozvati metu sa parametrima. Moguće je samo uslugu.
Ali koristim metu, 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 ostale (one su ionako simlinkovi na systemctl) svojim skriptom. Unutar skripta — prelazak u my_shutdown.target. A skripti unutar mete nakon toga direktno pozivaju systemctl, na primer, systemctl reboot
- Jednostavnija, ali mi se ne sviđa, opcija. U svim interfejsima pozivati ne shutdown/reboot/ostale, već direktno pozivati metu systemctl isolate my_shutdown.target
Izabrao sam prvu opciju. U systemd reboot (kao i poweroff) su simlinkovi na systemd.
ls -l \/sbin\/poweroff
lrwxrwxrwx 1 root root 14 sep 30 18:23 \/sbin\/poweroff -> \/bin\/systemctlZato ih možete zameniti svojim skriptima:
reboot
#!/bin/sh
touch /tmp/reboot
sudo systemctl isolate my_shutdown.target
fiZdroj: habr.com
