
Introductie
Bij het ontwikkelen onder Linux zijn er taken zoals het maken van interactieve scripts die worden uitgevoerd wanneer het systeem wordt in- of uitgeschakeld. In systeem V was dit eenvoudig te doen, maar met systemd worden er aanpassingen gemaakt. Het kan echter wel zijn eigen timers beheren.
Waarom hebben we doelstellingen nodig?
Er wordt vaak geschreven dat targets dienen als een analoog van runlevel in systeem V -init. Ik ben het daar fundamenteel mee oneens. Er zijn er meer en je kunt pakketten in groepen verdelen en bijvoorbeeld een groep services starten met één commando, en extra acties uitvoeren. Bovendien hebben ze geen hiërarchie, alleen afhankelijkheden.
Voorbeeld van doel wanneer ingeschakeld (functieoverzicht) met interactieve scriptlancering
Beschrijving van het doelwit zelf:
cat installer.target
[Unit]
Description=My installer
Requires=multi-user.target
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes
Wants=installer.serviceDit doel wordt gestart wanneer multi-user.target wordt gestart en installer.service wordt aangeroepen. Er kunnen meerdere van dergelijke services zijn.
cat installer.service
[Unit]
# описание
Description=installer interactive dialog
[Service]
# Запустить один раз, когда остальное будет запущенно
Type=idle
# Команда запуска - вызов скрипта
ExecStart=/usr/bin/installer.sh
# Интерактивное взаимодействие с пользователем через tty3
StandardInput=tty
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes
[Install]
WantedBy=installer.targetEn tot slot, een voorbeeld van een uitvoerbaar script:
#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answerHet belangrijkste is om final.target te selecteren: het doel dat het systeem moet bereiken bij het opstarten. Tijdens het opstartproces doorloopt systemd de afhankelijkheden en start alles wat nodig is.
Er zijn verschillende manieren om final.target te selecteren. Ik heb hiervoor de bootloaderoptie gebruikt.
De laatste run ziet er als volgt uit:
- De bootloader start
- De bootloader start de firmware-lancering door de parameter final.target door te geven
- Systemd start het systeem op. Het gaat sequentieel naar installer.target of work.target vanuit basic.target via hun afhankelijkheden (bijvoorbeeld multi-user.target). Deze laatste zorgen ervoor dat het systeem in de vereiste modus werkt.
De firmware voorbereiden voor lancering
Bij het aanmaken van firmware is er altijd een taak om de systeemstatus bij het opstarten te herstellen en bij het afsluiten op te slaan. De status omvat configuratiebestanden, databasedumps, interface-instellingen, enzovoort.
Systemd voert processen in één doel parallel uit. Er zijn afhankelijkheden waarmee u de volgorde van scriptstarts kunt bepalen.
Hoe het werkt in mijn project ( )
- Het systeem start
- De service settings_restore.service wordt gestart. Deze controleert of het bestand settings.txt in de datasectie aanwezig is. Als dit niet aanwezig is, wordt er een referentiebestand geplaatst. Vervolgens worden de systeeminstellingen hersteld:
- beheerderswachtwoord
- hostnaam,
- tijdzone
- locatie
- Bepalen of de volledige schijf wordt gebruikt. Standaard is de image klein, zodat kopiëren en schrijven naar de schijf gemakkelijker is. Bij het opstarten wordt gecontroleerd of er nog vrije ruimte is. Zo ja, dan wordt de schijf opnieuw gepartitioneerd.
- Genereer machine-ID op basis van MAC-adres. Dit is belangrijk om hetzelfde adres via DHCP te krijgen.
- Netwerkinstellingen
- De grootte van de logs is beperkt
- Er wordt een externe schijf voorbereid voor gebruik (als de overeenkomstige optie is ingeschakeld en de schijf nieuw is)
- PostgreSQ starten
- De herstelservice wordt gestart. Deze is nodig om Zabbix zelf en de bijbehorende database voor te bereiden:
- Controleert of er al een Zabbix-database bestaat. Zo niet, dan wordt deze aangemaakt op basis van initialisatiedumps (meegeleverd met Zabbix).
- er wordt een lijst met tijdzones gemaakt (nodig om ze in de webinterface weer te geven)
- Het huidige IP-adres is gevonden en wordt weergegeven in het probleem (uitnodiging om de console te betreden)
- De uitnodiging verandert - de zin Klaar om te werken verschijnt
- De firmware is klaar om te werken
De servicebestanden zijn belangrijk, zij bepalen de volgorde van hun lancering
[Unit]
Description=restore system settings
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.targetZoals u kunt zien, heb ik afhankelijkheden geïnstalleerd zodat mijn script eerst wordt uitgevoerd en pas daarna het netwerk wordt opgestart en het DBMS wordt gestart.
En de tweede dienst (het bereiden van zabbix)
#!/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.targetHet is hier iets ingewikkelder. De lancering vindt ook plaats in multi-user.target, maar NA de lancering van de postgresql DBMS en mijn setting_restore. Maar VÓÓR de lancering van de Zabbix-services.
Service met timer voor logrotate
Systemd kan CRON vervangen. Echt waar. En de nauwkeurigheid is niet tot op de minuut, maar tot op de seconde (wat als het nodig is). Of je kunt een monotone timer maken die wordt aangeroepen door een time-out van een gebeurtenis.
Het was precies deze monotone timer die de tijd aftelt vanaf het moment dat de machine die ik creëerde, werd gestart.
Hiervoor zijn 2 bestanden nodig
logrotateTimer.service — de feitelijke beschrijving van de service:
[Unit]
Description=run logrotate
[Service]
ExecStart=logrotate /etc/logrotate.conf
TimeoutSec=300Het is simpel: beschrijving van het lanceercommando.
Het tweede bestand logrotateTimer.timer zorgt ervoor dat de timers werken:
[Unit]
Description=Run logrotate
[Timer]
OnBootSec=15min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.targetWat is hier:
- timerbeschrijving
- Eerste uitvoeringstijd, vanaf het opstarten van het systeem
- periode van verdere lanceringen
- Afhankelijkheid van de timerservice. Deze regel doet feitelijk de timer.
Interactief script over afsluiten en uw eigen afsluitdoel
In een andere ontwikkeling moest ik een complexere versie van het afsluiten van de machine maken - via een eigen doel, om meerdere acties uit te voeren. Normaal gesproken wordt aanbevolen om een eenmalige service te maken met de optie RemainAfterExit, maar dit maakt het niet mogelijk om een interactief script te maken.
Het probleem is dat de opdrachten die door de optie ExecOnStop worden gestart, buiten de TTY worden uitgevoerd! Dit is eenvoudig te controleren: voer de tty-opdracht in en sla de uitvoer op.
Daarom heb ik de shutdown via mijn target geïmplementeerd. Ik beweer niet dat het 100% correct is, maar het werkt!
Hoe het werd gedaan (in algemene termen):
Een doel gemaakt, my_shutdown.target, dat van niemand afhankelijk is:
mijn_afsluiting.doel
[Unit]
Description=my shutdown
AllowIsolate=yes
Wants=my_shutdown.service Bij het overschakelen naar dit doel (via systemctl isolate my_shutdwn.target) werd de service my_shutdown.service gestart, waarvan de taak eenvoudig is: het uitvoeren van het script 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- In dit script voer ik de benodigde acties uit. Je kunt meerdere scripts aan het doel toevoegen voor meer flexibiliteit en gemak:
mijn_afsluiting.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/
$commandLet op: Gebruik de bestanden /tmp/reboot en /tmp/shutdown. Je kunt target niet met parameters aanroepen. Je kunt alleen service aanroepen.
Maar ik gebruik target om flexibiliteit in mijn werk te hebben en een gegarandeerde volgorde van handelingen.
Het meest interessante gebeurde echter later. De machine moet worden uitgezet en opnieuw opgestart. Er zijn twee opties:
- Vervang de reboot-, shutdown- en andere commando's (het zijn nog steeds symbolische links naar systemctl) door je eigen script. Ga in het script naar my_shutdown.target. De scripts in het target roepen dan systemctl rechtstreeks aan, bijvoorbeeld systemctl reboot.
- Een eenvoudigere optie, maar ik vind hem niet prettig. Roep in alle interfaces niet shutdown/reboot/others aan, maar roep de doelserver direct systemctl isolate my_shutdown.target aan.
Ik koos de eerste optie. In systemd staan bij reboot (en poweroff) symbolische links naar systemd.
ls -l /sbin/poweroff
lrwxrwxrwx 1 root root 14 сен 30 18:23 /sbin/poweroff -> /bin/systemctlZe kunnen daarom vervangen worden door uw eigen scripts:
opnieuw op te starten
#!/bin/sh
touch /tmp/reboot
sudo systemctl isolate my_shutdown.target
fiBron: www.habr.com
