
Introduktion
Når der udvikles til Linux, opstår der opgaver med at oprette interaktive scripts, der køres ved opstart eller nedlukning af systemet. I system V var det let, men med systemd er der ændringer. Til gengæld kan det håndtere sine egne timere.
Hvorfor er target nødvendige?
Det skrives ofte, at target fungerer som en pendant til runlevel i system V-init. Jeg er dybt uenig. Der er flere, og man kan gruppere pakker og for eksempel starte en gruppe tjenester med én kommando, udføre yderligere handlinger. Desuden er der ingen hierarki, kun afhængigheder.
Eksempel på target ved opstart (oversigt over muligheder) med kørsel af et interaktivt script.
Beskrivelse af selve target:
cat installer.target
[Unit]
Description=Min installer
Requires=multi-user.target
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes
Wants=installer.serviceDenne target startes, når multi-user.target er aktivt og vil kalde installer.service. Der kan være flere sådanne tjenester.
cat installer.service
[Unit]
# beskrivelse
Description=installer interaktiv dialog
[Service]
# Kør én gang, når det øvrige er startet
Type=idle
# Startkommando - kald script
ExecStart=/usr/bin/installer.sh
# Interaktiv interaktion med brugeren via tty3
StandardInput=tty
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes
[Install]
WantedBy=installer.targetOg endelig, et eksempel på det kørte script:
#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answerDet vigtigste er at vælge final.target - den target, systemet skal nå ved opstart. Under opstarten vil systemd følge afhængighederne og starte alt det nødvendige.
Final.target kan vælges på forskellige måder, jeg brugte loaderens mulighed til dette.
Den endelige opstart ser således ud:
- Loaderen starter
- Loaderen begynder at starte firmwaren og sender parameteren final.target
- Systemd begynder at starte systemet. Det går sekventielt til installer.target eller work.target fra basic.target gennem deres afhængigheder (for eksempel multi-user.target). De sidste bringer systemet til at fungere i den ønskede tilstand.
Forberedelse af firmwaren til opstart.
Når man opretter firmware, opstår der altid behov for at gendanne systemets tilstand ved opstart og gemme det ved nedlukning. Med tilstanden forstås konfigurationsfiler, databasesnapshots, interfaceindstillinger osv.
Systemd starter processer i en target parallelt. Der er afhængigheder, der gør det muligt at bestemme rækkefølgen for kørsel af scripts.
Sådan fungerer det i mit projekt ( )
- Systemet starter
- Tjenesten settings_restore.service startes. Den kontrollerer for tilstedeværelsen af filen settings.txt i datakatalogen. Hvis den ikke findes, erstattes den med en standardfil. Derefter foregår gendannelsen af systemindstillingerne:
- administratorens adgangskode
- hostname,
- tidszone
- lokalitet
- Bestemmelse af, om hele mediet anvendes. Som standard er størrelsen på billedet lille - for nem kopiering og skrivning til mediet. Ved opstart kontrolleres det - er der noget ubrugt plads. Hvis der er - ompartitioneres disken.
- Generering af machine-id fra MAC-adressen. Dette er vigtigt for at få den samme adresse via DHCP
- Netværksindstillinger
- Størrelsen på loggene begrænses
- Gør klar til at arbejde med den eksterne disk (hvis den relevante mulighed er aktiveret og disken er ny)
- PostgreSQL starter
- Tjenesten restore startes. Den er nødvendig for forberedelsen af Zabbix og dens database:
- Kontrollerer, om Zabbix-databasen allerede findes. Hvis ikke - oprettes den fra initialiseringsdumpene (de medfølger Zabbix)
- Oprettelse af en liste over tidszoner (nødvendig for visning i webgrænsefladen)
- Finder den aktuelle IP, den vises i issue (invitationen til at logge ind i konsollen)
- Indbydelsen ændres - sætningen 'Ready to work' vises
- Firmwaren er klar til brug
Det er vigtigt at have servicefilerne, de definerer rækkefølgen af deres opstart
[Unit]
Description=gendan systemindstillinger
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.targetSom du kan se, har jeg oprettet afhængigheder, så mit script kører først, hvorefter netværket starter, og databasesystemet startes.
Og den anden tjeneste (forberedelse af 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.targetHer er det lidt mere kompliceret. Starten er også i multi-user.target, men EFTER starten af databasesystemet PostgreSQL og mit setting_restore. Men FØR starten af Zabbix-tjenesterne.
Tjenesten med en timer til logrotate
Systemd kan erstatte CRON. Seriøst. Og præcisionen er ikke til minutter, men til sekunder (i tilfælde af at det er nødvendigt). Man kan også oprette en monoton timer, der kaldes ved timeout fra en begivenhed.
Det er netop en monoton timer, der tæller tiden fra maskinens opstart, jeg har oprettet.
For dette kræves der 2 filer
logrotateTimer.service - selve beskrivelsen af tjenesten:
[Unit]
Description=udfør logrotate
[Service]
ExecStart=logrotate \/etc\/logrotate.conf
TimeoutSec=300Alt er enkelt - beskrivelsen af startkommandoen.
Den anden fil, logrotateTimer.timer - den angiver timerens funktion:
[Unit]
Description=Kør logrotate
[Timer]
OnBootSec=15min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.targetHvad her er:
- timer beskrivelse
- Tid for første opstart, fra systemets opstart
- perioden for efterfølgende opstarter
- Afhængighed af timer-tjenesten. Faktisk er dette linjen, der gør timeren
Interaktivt script ved nedlukning og din nedluknings-target
I en anden udvikling måtte jeg lave en mere kompleks variant af maskinens nedlukning — gennem min egen target, for at udføre mange handlinger. Det anbefales normalt at oprette en oneshot service med indstillingen RemainAfterExit, men det tillader ikke at skabe et interaktivt script.
Det handler om, at kommandoerne, der køres med ExecOnStop-indstillingen, udføres uden for TTY! Det er nemt at kontrollere — indsæt kommandoen tty og gem dens output.
Derfor implementerede jeg nedlukning via min egen target. Jeg gør ikke krav på 100% korrekthed, men det fungerer!
Hvordan det blev gjort (i store træk):
Jeg oprettede my_shutdown.target, som ikke var afhængig af nogen:
my_shutdown.target
[Unit]
Description=min nedlukning
AllowIsolate=yes
Wants=my_shutdown.service Når man skifter til denne target (gennem systemctl isolate my_shutdown.target), starter den tjenesten my_shutdown.service, hvis opgave er simpel — at udføre scriptet my_shutdown.sh:
[Unit]
Description=MIN nedlukning
[Service]
Type=oneshot
ExecStart=\/usr\/bin\/my_shutdown.sh
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes
WantedBy=my_shutdown.target- Inde i dette script udfører jeg de nødvendige handlinger. Man kan tilføje mange scripts til target for fleksibilitet og bekvemmelighed:
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/
$commandBemærk. Brug af filer \/tmp\/reboot og \/tmp\/shutdown. Man kan ikke kalde target med parametre. Man kan kun kalde service.
Men jeg bruger target for at have fleksibilitet i arbejdet og garanteret rækkefølge af handlinger.
Dog var det mest interessante derefter. Maskinen skal slukkes/genstartes. Og her er der 2 muligheder:
- Erstat kommandoerne reboot, shutdown og andre (de er alligevel symboliske links til systemctl) med dit eget script. Inde i scriptet — skift til my_shutdown.target. Og scripts inde i target kalder derefter direkte systemctl, fx systemctl reboot
- En enklere, men jeg synes ikke om den, mulighed. I alle grænseflader kaldes det ikke shutdown/reboot/andre, men kaldes direkte target systemctl isolate my_shutdown.target
Jeg valgte den første mulighed. I systemd er reboot (ligesom poweroff) symboliske links til systemd.
ls -l \/sbin\/poweroff
lrwxrwxrwx 1 root root 14 sep 30 18:23 \/sbin\/poweroff -> \/bin\/systemctlDerfor kan de erstattes med egne scripts:
reboot
#!/bin/sh
touch /tmp/reboot
sudo systemctl isolate my_shutdown.target
fiKilde: habr.com
