
Ievads
Izstrādājot Linux vidē, rodas uzdevumi izveidot interaktīvus skriptus, kas tiek izpildīti, ieslēdzot vai izslēdzot sistēmu. System V to bija viegli izdarīt, bet ar systemd ir nepieciešamas izmaiņas. Tomēr tam ir savi taimeri.
Kāpēc ir vajadzīgi target
Bieži tiek rakstīts, ka target ir līdzīgi kā runlevel system V -init. Es ar to kategoriski nepiekrītu. To ir vairāk, un var grupēt pakotnes, piemēram, izpildīt vienā komandā grupu pakalpojumu, veicot papildu darbības. Turklāt tiem nav hierarhijas, tikai atkarības.
Target piemērs ieslēgšanai (iespēju apskate) ar interaktīvā skripta izsaukšanu
Pats target apraksts:
cat installer.target
[Unit]
Description=Mani izmantošanas rīki
Requires=multi-user.target
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes
Wants=installer.serviceŠis target tiks aktivizēts, kad tiks palaists multi-user.target un izsauks installer.service. Tajā pašā laikā var būt vairāki šādu pakalpojumu.
cat installer.service
[Unit]
# apraksts
Description=instalācijas interaktīvā dialoga
[Service]
# Izpildīt vienu reizi, kad viss pārējais būs palaists
Type=idle
# Izpildes komanda - skripta izsaukums
ExecStart=\/usr\/bin\/installer.sh
# Interaktīva mijiedarbība ar lietotāju caur tty3
StandardInput=tty
TTYPath=\/dev\/tty3
TTYReset=yes
TTYVHangup=yes
[Install]
WantedBy=installer.targetUn visbeidzot, izpildāmā skripta piemērs:
#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answerVisnosvarīgākais ir izvēlēties final.target – target, uz kuru sistēma jānonāk, palaižot to. Ieslēgšanas procesā systemd izies cauri atkarībām un palaidīs visu nepieciešamo.
Final.target var izvēlēties dažādos veidos, es izmantoju tam paredzēto ielādes opciju.
Galīgā palaišana izskatās šādi:
- Sākas ielāde
- Ielādes programma sāk palaist apmācību, nododot parametru final.target
- Systemd sāk sistēmas palaišanu. Secīgi pārvietojas uz installer.target vai work.target no basic.target caur to atkarībām (piemēram, multi-user.target). Pēdējie noved sistēmu nepieciešamajā režīmā.
Apmācības sagatavošana palaišanai
Izstrādājot apmācības, vienmēr rodas uzdevums atjaunot sistēmas stāvokli palaišanas laikā un to saglabāt izslēgšanas laikā. Apakšā tiek saprasti konfigurācijas faili, datu bāzu atmiņas, saskarnes iestatījumi u.c.
Systemd palaiž procesus vienā target paralēli. Pastāv atkarības, kas nosaka skriptu izsaukšanas secību.
Kā tas strādā manā projektā ( )
- Sistēma startē
- Tiek uzsākts settings_restore.service. Tas pārbauda, vai datu sadaļā ir pieejams fails settings.txt. Ja tāda nav, tā vietā tiek novietots etalona fails. Pēc tam notiek sistēmas iestatījumu atjaunošana:
- administratora parole
- hostname,
- laika zona
- lokalitāte
- Nosaka, vai tiek izmantots viss nesējs. Noklusējuma attēla izmērs ir neliels — lai vienkāršotu dublēšanu un ierakstīšanu nesējā. Palaides laikā tiek pārbaudīts, vai ir pieejama brīva vieta. Ja ir — disks tiek pārparticionēts.
- Machine-id ģenerēšana no MAC adreses. Tas ir svarīgi, lai saņemtu to pašu adresi pa DHCP
- Tīkla iestatījumi
- Ierobežo žurnālu lielumu
- Tiek sagatavota ārējā diska darbība (ja ir ieslēgta attiecīgā opcija un disks ir jauns)
- Sākas postgresq
- tiek uzsākts restore serviss. Tas ir nepieciešams, lai sagatavotu pašu zabbix un tā datubāzi:
- Tiek pārbaudīts, vai zabbix datubāze jau pastāv. Ja nē — tā tiek izveidota no sākuma iestatīšanas dublējumam (kas nāk kopā ar zabbix)
- Tiek izveidots laika zonu saraksts (nepieciešams to attēlošanai tīmekļa saskarsmē)
- Tiek noskaidrots pašreizējais IP, kas tiek parādīts issue (aicinājumā uz konsoli)
- Izsaukuma aicinājums tiek mainīts — parādās frāze Ready to work
- Programmatūra ir gatava darbam
Svarīgi ir pakalpojumu faili, tie nosaka to palaišanas secību
[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.targetKā redzams, es esmu norādījis atkarības, lai vispirms tiktu izpildīts mans skripts, un tikai pēc tam tiktu uzsākta tīkls un datubāze.
Un otrais serviss (zabbix sagatavošana)
#!/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Šeit ir nedaudz sarežģītāk. Palaide notiek arī multi-user.target, bet PĒC postgresql datubāzes un mana settings_restore palaišanas. Bet PIRMS zabbix pakalpojumu uzsākšanas.
Serviss ar taimeri logrotate
Systemd var aizstāt CRON. Tiešām. Turklāt precizitāte ir nevis līdz minūtei, bet līdz sekundei (ja nu jā). Var izveidot monotoni taimeri, kas tiek aicināts pēc laika no notikuma.
Tieši tāds monotons taimeris, kas skaita laiku kopš mašīnas palaišanas, es esmu izveidojis.
Tam būs nepieciešami 2 faili
logrotateTimer.service — faktiskā pakalpojuma apraksts:
[Unit]
Description=run logrotate
[Service]
ExecStart=logrotate /etc/logrotate.conf
TimeoutSec=300Viss ir vienkārši — komandas palaišanas apraksts.
Otrais fails logrotateTimer.timer — tas nosaka taimeru darbību:
[Unit]
Description=Run logrotate
[Timer]
OnBootSec=15min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.targetKas šeit ir:
- taimeru apraksts
- Pirmās palaišanas laiks, sākot no sistēmas ielādes
- atsevišķo palaidiens periods
- Atkarība no taimeru pakalpojumiem. Faktiski tas ir rinda un veido taimeri
Interaktīvais skripts izslēgšanās laikā un tā mērķis izslēgšanai
Citā izstrādē man bija jāizveido sarežģītāka mašīnas izslēgšanas variantu — caur savu mērķi, lai veiktu daudzas darbības. Parasti ieteicams izveidot oneshot pakalpojumu ar opciju RemainAfterExit, taču tas neļauj izveidot interaktīvu skriptu.
Problēma ir tāda, ka komandas, kas palaidētas ar ExecOnStop opciju, tiek izpildītas ārpus TTY! Pārbaudīt ir vienkārši — ievietojiet komandu tty un saglabājiet tās izvadi.
Tāpēc es īstenoju izslēgšanu caur savu mērķi. 100% pareizību nesolu, bet tas strādā!
Kā tas tika izdarīts (vispārīgās līnijās):
Izveidoju mērķi my_shutdown.target, kas nebija atkarīgs no neviena:
my_shutdown.target
[Unit]
Description=my shutdown
AllowIsolate=yes
Wants=my_shutdown.service Pārējot uz šo mērķi (caur systemctl isolate my_shutdwn.target), tas sāk my_shutdown.service pakalpojumu, kura uzdevums ir vienkāršs — izpildīt skriptu 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- Šī skripta iekšienē es izpildīju vajadzīgās darbības. Mērķī var pievienot daudz skriptu, lai uzlabotu elastību un ērtumu:
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/
$commandPiezīme. Lietojot failus \/tmp\/reboot un \/tmp\/shutdown. Nav iespējams izsaukt mērķi ar parametru palīdzību. Var tikai izsaukt pakalpojumu.
Tomēr es izmantoju mērķi, lai iegūtu elastību darbā un garantētu darbību izpildes secību.
Tomēr interesantākais bija vēlāk. Mašīnu taču vajag izslēgt\/pārstartēt. Un šeit ir divi varianti:
- Aizvietot komandas reboot, shutdown un citas (tie tomēr ir simboliskie linki uz systemctl) ar savu skriptu. Skripta iekšienē — pāreja uz my_shutdown.target. Un skripti iekš mērķi pēc tam tieši izsauc systemctl, piemēram, systemctl reboot
- Vienkāršāks, bet man nepatīk variants. Visās saskarnēs izsaukt ne shutdown\/reboot\/citām, bet tieši izsaukt mērķi systemctl isolate my_shutdown.target
Es izvēlējos pirmo variantu. Systemd reboot (kā arī poweroff) ir simboliskie linki uz systemd.
ls -l \/sbin\/poweroff
lrwxrwxrwx 1 root root 14 sep 30 18:23 \/sbin\/poweroff -> \/bin\/systemctlTāpēc tos var aizvietot ar saviem skriptiem:
reboot
#!/bin/sh
touch /tmp/reboot
sudo systemctl isolate my_shutdown.target
fiAvots: habr.com
