6 modulis · 6.3
Nuosavos paslaugos ir laikmačiai
6 modulis: Paslaugos ir žurnalai · Skaitymo laikas: 11 min.
Mokymosi tikslas: Po šios pamokos galėsite paleisti savo programą kaip systemd paslaugą, veikiančią atskiro naudotojo vardu ir su keliomis saugumo parinktimis, bei planuoti užduotis su systemd laikmačiu (timer) arba cron.
Pagrindinės sąvokos: unit failas, [Unit], [Service], [Install], ExecStart, User=, WorkingDirectory, EnvironmentFile, Restart=, WantedBy, NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, systemd-analyze security, laikmatis (timer), OnCalendar, Persistent, crontab
Kodėl ne tiesiog "nohup" ar "screen"?
Kas į serverį įdiegia savo programą (nedidelę žiniatinklio programą, botą, scenarijų, kuris kiekvieną naktį ką nors atlieka), pirmą kartą ją dažnai paleidžia rankiniu būdu: node server.js & arba screen sesijoje. Tai veikia, kol atsijungiate, serveris paleidžiamas iš naujo arba programa sutrinka. Tada ji dingsta, ir niekas to nepastebi.
Programa, kuri turi veikti visada, turėtų būti systemd paslauga. Tada:
- ji pasileidžia savaime įjungiant serverį;
- systemd ją paleidžia iš naujo, jei ji sutrinka;
- jos išvestis patenka į žurnalą (journal, pamoka 6.2);
- ji veikia Jūsų pasirinkto naudotojo vardu ir su tomis teisėmis, kurias Jūs leidžiate.
Nuosavas unit failas
Tarkime, turite nedidelę Node.js programą kataloge /opt/factuurapp, kuri klausosi 127.0.0.1:3000. Vėliau nginx arba Caddy ją padarys pasiekiamą iš išorės (modulis 7).
1 žingsnis: atskiras naudotojas be apvalkalo (shell) (pamoka 3.2). Programai nereikia būti root ir nereikia prisijungti:
anna@web1:~$ sudo adduser --system --group --home /opt/factuurapp --no-create-home factuurapp
anna@web1:~$ sudo chown -R factuurapp:factuurapp /opt/factuurapp/dataPats kodas gali likti priklausyti root (programai nereikia savęs keisti); dienos naudotojui priklauso tik katalogas, į kurį ji rašo.
2 žingsnis: unit failas. Nuosavus unit failus dėkite į /etc/systemd/system/:
# /etc/systemd/system/factuurapp.service
[Unit]
Description=Factuurapp (Node.js)
After=network-online.target
Wants=network-online.target
[Service]
User=factuurapp
Group=factuurapp
WorkingDirectory=/opt/factuurapp
EnvironmentFile=/etc/factuurapp/env
ExecStart=/usr/bin/node /opt/factuurapp/server.js
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/opt/factuurapp/data
[Install]
WantedBy=multi-user.targetTrys blokai:
- [Unit]: aprašymas ir eiliškumas.
After=network-online.targetkartu suWants=užtikrina, kad paslauga pasileistų tik tada, kai tinklas jau veikia. - [Service]: kaip programa veikia.
ExecStartsu visu keliu (systemd nenaudoja paieškos kelio, kaip Jūsų apvalkalas).User=irGroup=nustato, kieno vardu ji veikia.EnvironmentFilenuskaito nustatymus, pavyzdžiui, duomenų bazės slaptažodį, iš atskiro failo, kad jų nebūtų unit faile. - [Install]: ką daro
enable.WantedBy=multi-user.targetreiškia: paleisti kartu su įprastu sistemos paleidimu.
3 žingsnis: paslaptys atskirai, su griežtomis teisėmis.
anna@web1:~$ sudo mkdir /etc/factuurapp
anna@web1:~$ sudo install -m 600 -o root -g root /dev/null /etc/factuurapp/env
anna@web1:~$ sudoedit /etc/factuurapp/envTurinys, pavyzdžiui, DATABASE_URL=postgres://factuur:...@127.0.0.1/factuur. systemd nuskaito failą kaip root prieš persijungdama į paslaugos naudotoją, todėl pakanka 600, priklausančio root.
4 žingsnis: įkelti, paleisti, patikrinti.
anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now factuurapp
anna@web1:~$ systemctl status factuurapp
anna@web1:~$ journalctl -u factuurapp -fSaugumo parinktys: mažai pastangų, didelis skirtumas
Keturios eilutės po RestartSec pavyzdyje apriboja, ką paslauga gali daryti, net jei kas nors randa spragą Jūsų programoje:
| Parinktis | Poveikis |
|---|---|
NoNewPrivileges=true | procesas ir jo vaikiniai procesai niekada negali gauti daugiau teisių (net per sudo ar setuid programas) |
ProtectSystem=strict | visa failų sistema paslaugai yra tik skaitoma, išskyrus tai, ką leidžiate su ReadWritePaths= |
ProtectHome=true | /home, /root ir /run/user yra nematomi |
PrivateTmp=true | atskiras, tuščias /tmp, kurio kitos programos nemato |
systemd gali įvertinti Jūsų unit failą:
anna@web1:~$ systemd-analyze security factuurapp
...
→ Overall exposure level for factuurapp.service: 4.9 OK 🙂Kuo mažesnis skaičius, tuo geriau. Paslauga be parinkčių gauna apie 9 ("UNSAFE"). Siekti nulio nebūtina: kiekviena pridėta parinktis gali sugadinti tai, ko programai reikia. Pridėkite jas po vieną ir po kiekvieno žingsnio išbandykite. Jei kas nors nustoja veikti, priežastis dažniausiai matoma žurnale ("Read-only file system", "Permission denied").
Užduočių planavimas: laikmačiai
Tam, kas turi vykti nustatytu laiku (atsarginė kopija, valymo scenarijus, ataskaita), reikia laikmačio (timer). systemd laikmatį sudaro du unit failai tuo pačiu pavadinimu: .service, kuris nurodo, kas turi būti atlikta, ir .timer, kuris nurodo, kada.
# /etc/systemd/system/opruimen.service
[Unit]
Description=Oude exportbestanden opruimen
[Service]
Type=oneshot
User=factuurapp
ExecStart=/usr/bin/find /opt/factuurapp/data/export -type f -mtime +30 -delete# /etc/systemd/system/opruimen.timer
[Unit]
Description=Dagelijks oude exportbestanden opruimen
[Timer]
OnCalendar=*-*-* 03:15:00
RandomizedDelaySec=10m
Persistent=true
[Install]
WantedBy=timers.targetType=oneshot reiškia: programa paleidžiama ir po to baigia darbą. OnCalendar yra tvarkaraštis: kasdien 03:15. Taip pat galite rašyti daily, weekly arba Mon *-*-* 02:00; systemd-analyze calendar "Mon *-*-* 02:00" parodo, kada bus kitas paleidimas. Persistent=true yra svarbus: jei 03:15 serveris buvo išjungtas, užduotis vis tiek bus atlikta iškart po paleidimo. RandomizedDelaySec šiek tiek išsklaido paleidimo momentą.
Įjungiamas laikmatis, ne paslauga:
anna@web1:~$ sudo systemctl daemon-reload
anna@web1:~$ sudo systemctl enable --now opruimen.timer
anna@web1:~$ systemctl list-timers opruimen
NEXT LEFT LAST PASSED UNIT ACTIVATES
Tue 2026-11-10 03:19:42 CET 15h left - - opruimen.timer opruimen.service
anna@web1:~$ sudo systemctl start opruimen.service # dabar vieną kartą išbandyti rankiniu būdu
anna@web1:~$ journalctl -u opruimen.serviceO kaip cron?
cron yra senesnis, paprastesnis įrankis ir vis dar puikiai veikia. Eilutė naudotojo crontab faile (crontab -e):
15 3 * * * /usr/local/bin/opruimen.shPenki laukai yra minutė, valanda, mėnesio diena, mėnuo ir savaitės diena. Privalumai ir trūkumai greta:
| cron | systemd laikmatis | |
|---|---|---|
| Sąranka | viena eilutė | du failai |
| Praleistas paleidimas (serveris išjungtas) | praleidžiamas | su Persistent=true atliekamas vėliau |
| Išvestis ir klaidos | el. paštu, jei serveris gali siųsti laiškus; kitaip dingsta | žurnale |
| Saugumo parinktys, naudotojas | per patį scenarijų | visos systemd galimybės (žr. aukščiau šioje pamokoje) |
| Matyti, kada jis veikė | sudėtinga | systemctl list-timers ir žurnalas |
Serveriui, kurį administruojate rimtai, laikmačiai yra geresnis pasirinkimas, ypač atsarginėms kopijoms (pamoka 8.2): norite tiksliai žinoti, kad jos buvo atliktos ir ką jos pranešė. Cron eilutę, kuri tyliai nepavyksta, pastebėsite tik tada, kai Jums prireiks atsarginės kopijos.
AlmaLinux ir Rocky Linux sistemose
Unit failai ir laikmačiai veikia lygiai taip pat. Vienas skirtumas: SELinux gali blokuoti nuosavą paslaugą, kuri skaito ar rašo failus vietoje, kurios SELinux nesitiki, arba klausosi neįprasto prievado. Pranešimas pateikiamas /var/log/audit/audit.log. Neišjunkite SELinux, kad išspręstumėte problemą; raskite tinkamą žymę arba taisyklę (pavyzdžiui, su semanage).
Santrauka
- Programa, kuri turi veikti visada, turėtų būti systemd paslauga: paleidžiama savaime, paleidžiama iš naujo sutrikus, žurnalai patenka į journal.
- Nuosavi unit failai dedami į
/etc/systemd/system/, suUser=nurodomas atskiras naudotojas be apvalkalo, paslaptys laikomosEnvironmentFilesu teisėmis 600. NoNewPrivileges,ProtectSystem=strictsuReadWritePaths,ProtectHomeirPrivateTmpsumažina žalą įvykus spragai;systemd-analyze securityįvertina unit failą.- Laikmatis yra
.serviceir.timersuOnCalendar;Persistent=trueatlieka praleistus paleidimus. Įjunkite laikmatį, o ne paslaugą. - cron vis dar veikia, bet laikmačiai suteikia geresnius žurnalus ir nepraleidžia paleidimų.
Testas (quiz)
Užduotis
Užduotis O6.3: Nuosava paslauga su laikmačiu. Sukurkite savo serveryje nedidelę nuosavą paslaugą su laikmačiu, pavyzdžiui, scenarijų, kuris kiekvieną naktį įrašo laisvą disko vietą ir systemctl --failed į failą arba žurnalą. Naudokite atskirą naudotoją, Type=oneshot, bent dvi saugumo parinktis ir Persistent=true. Išbandykite su systemctl start, peržiūrėkite išvestį žurnale ir užsirašykite systemd-analyze security įvertinimą. Įklijuokite savo .service ir .timer ir atsakykite į kontrolinio sąrašo klausimus.
Užduotis O6.3: Nuosava paslauga su laikmačiu
Šią užduotį atliekate patys; niekas jos netikrina. Pažymėkite, ką atlikote, ir pažymėkite užduotį kaip atliktą.
Su Persistent=true užduotis vis tiek įvykdoma po paleidimo. Įvertinimas žemiau 6 yra geras pirmajai paslaugai; rašymo teisės tik per ReadWritePaths.
Jūsų pažymėti varneliai ir pastabos lieka tik šioje naršyklėje; niekur jų nesiunčiame. Jei esate prisijungę, skiltyje Mano kursai išsaugome tik tai, kad užduotį atlikote.
Skaitykite daugiau
- DirectAdmin vadovas 15.1: Periodinės užduotys: automatinis užduočių vykdymas
- Vadovas
systemd.exec(5)(User=, ProtectSystem=, NoNewPrivileges=): https://manpages.debian.org/trixie/systemd/systemd.exec.5.en.html - Vadovas
systemd.timer(5)(OnCalendar=, Persistent=): https://manpages.debian.org/trixie/systemd/systemd.timer.5.en.html - Vadovas
systemd.time(7)(tvarkaraščiai): https://manpages.debian.org/trixie/systemd/systemd.time.7.en.html
