Systemd, interaktive skript og timere

Systemd, interaktive skript og timere

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.service

Denne 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.target

Og til slutt, et eksempel på et skript som kjøres:

#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answer

Det 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:

  1. Lastestarteren starter
  2. Lastestarteren begynner å starte firmware, og sender parameteret final.target
  3. 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 ( https://habr.com/ru/post/477008/ https://github.com/skif-web/monitor)

  1. Systemet starter
  2. 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)
  3. postgresq starter
  4. 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)
  5. Promptet endres — setningen Ready to work vises
  6. 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.target

Som 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.target

Her 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=300

Alt 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.target

Hva 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/
    $command

Merk. 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\/systemctl

Derfor kan de erstattes med egne skript:
reboot

#!/bin/sh
    touch /tmp/reboot
    sudo systemctl isolate my_shutdown.target
fi

Kilde: habr.com

Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster