
Innledning
Når du utvikler for linux, oppstår det oppgaver med å lage interaktive skript som kjøres ved oppstart eller nedstengning av systemet. I system V var dette enkelt, men med systemd er det gjort noen endringer. Det kan imidlertid bruke sine egne tidtakere.
Hvorfor trengs target
Det skrives ofte at target fungerer som et analogt runlevel i system V -init. Jeg er helt uenig. Det er flere, og man kan dele opp pakkene i grupper og ved for eksempel starte en gruppe tjenester med en kommando, utføre tilleggsoppgaver. I tillegg har de ingen hierarki, kun avhengigheter.
Eksempel på target ved oppstart (oversikt over muligheten) med kjøring av interaktivt skript
Beskrivelse av selve target:
cat installer.target
[Enhet]
Beskrivelse=My installer
Krever=multi-user.target
Konflikter=rescue.service rescue.target
Etter=multi-user.target rescue.service rescue.target
TillatIsolasjon=yes
Ønsker=installer.serviceDenne target vil starte når multi-user.target er startet og vil kalle installer.service. Det kan imidlertid være flere slike tjenester.
cat installer.service
[Enhet]
# beskrivelse
Beskrivelse=installer interaktiv dialog
[Tjeneste]
# Kjøre én gang, når alt annet er startet
Type=idle
# Startkommando - kall skriptet
ExecStart=\/usr\/bin\/installer.sh
# Interaktiv interaksjon med bruker gjennom tty3
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes
[Installer]
ØnsketAv=installer.targetOg til slutt, et eksempel på et skript som kjøres:
#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answerDet viktigste er å velge final.target - target som systemet skal gå til ved oppstart. Under oppstarten vil systemd gå gjennom avhengighetene og starte alt som er nødvendig.
Du kan velge final.target på forskjellige måter, jeg brukte for dette lastalternativet.
Den endelige oppstarten ser slik ut:
- Lastestarteren starter
- Lastestarteren begynner å starte firmware, og sender parameteret final.target
- Systemd begynner å starte systemet. Det går sekvensielt til installer.target eller work.target fra basic.target gjennom deres avhengigheter (for eksempel multi-user.target). De sistnevnte fører systemet til å fungere i ønsket modus.
Forberedelse av firmware for oppstart
Når man lager firmware, oppstår alltid oppgaven med å gjenopprette systemstatus ved oppstart og bevare den ved nedstenging. Med status forstås konfigurasjonsfiler, databasedumps, grensesnittinnstillinger osv.
Systemd starter prosesser i en target parallelt. Det finnes avhengigheter som gjør at man kan bestemme rekkefølgen i oppstarten av skriptene.
Slik fungerer det hos meg i prosjektet ( )
- Systemet starter
- Tjenesten settings_restore.service starter. Den sjekker om filen settings.txt finnes i dataseksjonen. Hvis ikke, plasseres en standardfil der i stedet. Deretter skjer gjenopprettingen av systeminnstillingene:
- administratorpassordet
- hostname,
- tidssone
- lokale
- Fastslå om hele enheten brukes. Som standard er størrelsen på bildet liten — for enkel kopiering og skriving til enheten. Ved oppstart sjekkes det om det er ubrukt plass. Hvis det er, blir disken ompartisjonert.
- Generering av machine-id fra MAC-adressen. Dette er viktig for å få den samme adressen via DHCP.
- Nettverksinnstillinger
- Størrelsen på loggene begrenses
- Forbereder seg på å arbeide med en ekstern disk (hvis relevant alternativ er aktivert og disken er ny)
- postgresq starter
- tjenesten restore starter. Den er nødvendig for å forberede selve zabbix og databasen dens:
- Det sjekkes om det allerede finnes en zabbix-database. Hvis ikke, opprettes den fra initialiserings-dumpene (som følger med zabbix).
- en liste over tidssoner opprettes (nødvendig for å vise dem i webgrensesnittet)
- Den nåværende IP-en finnes, og den vises i issue (forespørsel for å logge inn i konsollen)
- Promptet endres — setningen Ready to work vises
- Firmware er klar til bruk
Filer med tjenester er viktige, da de bestemmer rekkefølgen for oppstart.
[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.targetSom du ser, har jeg satt opp avhengigheter for at skriptet mitt skal kjøres først, og deretter nettverket og DB-en skal startes.
Og den andre tjenesten (forberedelse av 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 litt mer komplisert. Oppstart skjer også i multi-user.target, men ETTER oppstart av DB-en postgresql og mitt setting_restore. Men FØR oppstart av zabbix-tjenestene.
Tjeneste med en timer for logrotate
Systemd kan erstatte CRON. Seriøst. Og nøyaktigheten er ikke til minutt, men til sekund (bare hvis det trengs). Det er også mulig å lage en monoton timer, som kalles på timeout fra et event.
Det er nettopp en monoton timer, som teller tiden fra maskinens oppstart, jeg har laget.
For dette kreves det 2 filer
logrotateTimer.service — selve tjenestebeskrivelsen:
[Unit]
Description=run logrotate
[Service]
ExecStart=logrotate \/etc\/logrotate.conf
TimeoutSec=300Alt er enkelt — beskrivelse av oppstartskommandoen.
Den andre filen logrotateTimer.timer — den setter opp timerens arbeid:
[Unit]
Description=Run logrotate
[Timer]
OnBootSec=15min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.targetHva er det her:
- beskrivelse av timer
- Tiden for første oppstart, fra systemlastingen
- perioden for påfølgende oppstarter
- Avhengighet til timer-tjenesten. Faktisk er dette linjen som lager timeren
Interaktivt skript ved avstenging og din avstengingsmålsetning
I en annen utvikling måtte jeg lage en mer komplisert versjon av å slå av maskinen — gjennom egen målsetning, for å utføre mange handlinger. Det anbefales vanligvis å opprette en oneshot-tjeneste med RemainAfterExit-alternativet, men det lar ikke en lage et interaktivt skript.
Saken er at kommandoene som kjøres med ExecOnStop-alternativet kjører uten TTY! Sjekk enkelt — sett inn kommandoen tty og lagre utdataene.
Derfor implementerte jeg avstenging gjennom egen målsetning. Jeg hevder ikke 100% riktighet, men det fungerer!
Slik ble det gjort (i store trekk):
Opprettet målsetning my_shutdown.target, som ikke hadde avhengighet til noen:
my_shutdown.target
[Unit]
Description=min avstenging
AllowIsolate=yes
Wants=my_shutdown.service Ved å gå til denne målsetningen (via systemctl isolate my_shutdown.target), startet den tjenesten my_shutdown.service, hvis oppgave er enkel — å utføre skriptet my_shutdown.sh:
[Unit]
Description=MIN avstenging
[Service]
Type=oneshot
ExecStart=\/usr\/bin\/my_shutdown.sh
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes
WantedBy=my_shutdown.target- Inne i dette skriptet utfører jeg nødvendige handlinger. Man kan legge til mange skript i målsetningen for fleksibilitet og bekvemmelighet:
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/
$commandMerk. Bruken av filer \/tmp\/reboot og \/tmp\/shutdown. Man kan ikke kalle målsetningen med parametere. Man kan bare kalle tjenesten.
Men jeg bruker målsetning for å ha fleksibilitet i arbeidet og garantert rekkefølge for utførelsen av oppgaver.
Men det mest interessante kom senere. Maskinen må jo slås av\/startes på nytt. Og her er det to alternativer:
- Erstatte kommandoene reboot, shutdown og andre (de er tross alt symlinker til systemctl) med sitt eget skript. Inne i skriptet — gå til my_shutdown.target. Og skriptene inne i målsetningen kaller deretter systemctl direkte, for eksempel systemctl reboot.
- En enklere, men jeg liker ikke det, variant. I alle grensesnitt kalle ikke shutdown\/reboot\/andre, men ringe målsetningen direkte systemctl isolate my_shutdown.target.
Jeg valgte den første varianten. I systemd er reboot (som og poweroff) symlinker til systemd.
ls -l \/sbin\/poweroff
lrwxrwxrwx 1 root root 14 sep 30 18:23 \/sbin\/poweroff -> \/bin\/systemctlDerfor kan de erstattes med egne skript:
reboot
#!/bin/sh
touch /tmp/reboot
sudo systemctl isolate my_shutdown.target
fiKilde: habr.com
