GNU/Linux >> Linux Esercitazione >  >> Linux

Gestisci l'avvio usando systemd

Durante la configurazione di un sistema Linux di recente, volevo sapere come garantire che le dipendenze per i servizi e altre unità fossero attive e funzionanti prima dell'avvio di tali servizi e unità dipendenti. In particolare, avevo bisogno di maggiori conoscenze su come systemd gestisce la sequenza di avvio, in particolare per determinare che i servizi degli ordini vengano avviati in quello che è essenzialmente un sistema parallelo.

Potresti sapere che SystemV (il predecessore di systemd, come ho spiegato nel primo articolo di questa serie) ordina la sequenza di avvio nominando gli script di avvio con un prefisso SXX, dove XX è un numero da 00 a 99. SystemV utilizza quindi l'ordinamento per nome ed esegue ogni script di avvio in sequenza per il runlevel desiderato.

Ma systemd utilizza file di unità, che possono essere creati o modificati da un amministratore di sistema, per definire le subroutine non solo per l'inizializzazione ma anche per il normale funzionamento. Nel terzo articolo di questa serie, ho spiegato come creare un file di unità di montaggio. In questo quinto articolo, mostro come creare un diverso tipo di file di unità, un file di unità di servizio che esegue un programma all'avvio. Puoi anche modificare alcune impostazioni di configurazione nel file dell'unità e utilizzare il diario di sistema per visualizzare la posizione delle modifiche nella sequenza di avvio.

Preparazione

Assicurati di aver rimosso rhgb e quiet dal GRUB_CMDLINE_LINUX= riga nel /etc/default/grub file, come ho mostrato nel secondo articolo di questa serie. Ciò ti consente di osservare il flusso di messaggi di avvio di Linux, di cui avrai bisogno per alcuni degli esperimenti in questo articolo.

Il programma

In questo tutorial creerai un semplice programma che ti consentirà di osservare un messaggio durante l'avvio sulla console e successivamente nel diario di sistema.

Crea il programma shell /usr/local/bin/hello.sh e aggiungi il seguente contenuto. Vuoi assicurarti che il risultato sia visibile durante l'avvio e che tu possa trovarlo facilmente quando guardi nel diario di sistema. Utilizzerai una versione del programma "Hello world" con alcune barre intorno, quindi risalta. Assicurati che il file sia eseguibile e abbia la proprietà di utenti e gruppi da root con 700 autorizzazioni per la sicurezza:

#!/usr/bin/bash
# Simple program to use for testing startup configurations
# with systemd.
# By David Both
# Licensed under GPL V2
#
echo "###############################"
echo "######### Hello World! ########"
echo "###############################"

Esegui questo programma dalla riga di comando per verificare che funzioni correttamente:

[root@testvm1 ~]# hello.sh 
###############################
######### Hello World! ########
###############################
[root@testvm1 ~]#

Questo programma può essere creato in qualsiasi linguaggio di scripting o compilato. Il hello.sh il programma potrebbe anche essere posizionato in altri luoghi in base alla struttura gerarchica del filesystem (FHS) di Linux. Lo metto in /usr/local/bin directory in modo che possa essere facilmente eseguito dalla riga di comando senza dover anteporre un percorso quando digito il comando. Trovo che molti dei programmi shell che creo debbano essere eseguiti dalla riga di comando e da altri strumenti come systemd.

Il file dell'unità di servizio

Crea il file dell'unità di servizio /etc/systemd/system/hello.service con il seguente contenuto. Non è necessario che questo file sia eseguibile, ma per sicurezza richiede la proprietà di utenti e gruppi tramite root e autorizzazioni 644 o 640:

# Simple service unit file to use for testing 
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh

[Install]
WantedBy=multi-user.target

Verificare che il file dell'unità di servizio funzioni come previsto visualizzando lo stato del servizio. Eventuali errori sintattici verranno visualizzati qui:

[root@testvm1 ~]# systemctl status hello.service 
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)
[root@testvm1 ~]#

Puoi eseguire questo tipo di servizio "oneshot" più volte senza problemi. Il tipo oneshot è destinato ai servizi in cui il programma avviato dal file dell'unità di servizio è il processo principale e deve essere completato prima che systemd avvii qualsiasi processo dipendente.

Esistono sette tipi di servizio e puoi trovare una spiegazione di ciascuno (insieme alle altre parti di un file dell'unità di servizio) nella pagina man systemd.service(5). (Puoi anche trovare maggiori informazioni nelle risorse alla fine di questo articolo.)

Per quanto sia curioso, volevo vedere come potrebbe essere un errore. Quindi, ho eliminato la "o" da Type=oneshot linea, quindi sembrava Type=neshot e ho eseguito di nuovo il comando:

[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 06 08:50:09 testvm1.both.org systemd[1]: /etc/systemd/system/hello.service:12: Failed to parse service type, ignoring: neshot
[root@testvm1 ~]#

Questi risultati mi hanno indicato esattamente dove si trovava l'errore e hanno semplificato la risoluzione del problema.

Più risorse Linux

  • Comandi Linux cheat sheet
  • Cheat sheet sui comandi avanzati di Linux
  • Corso online gratuito:Panoramica tecnica RHEL
  • Cheat sheet della rete Linux
  • Cheat sheet di SELinux
  • Cheat sheet dei comandi comuni di Linux
  • Cosa sono i container Linux?
  • I nostri ultimi articoli su Linux

Tieni presente che anche dopo aver ripristinato hello.service file nella sua forma originale, l'errore persisterà. Sebbene un riavvio cancellerà l'errore, non dovresti farlo, quindi sono andato alla ricerca di un metodo per eliminare errori persistenti come questo. Ho riscontrato errori di servizio che richiedono il comando systemctl daemon-reload per ripristinare una condizione di errore, ma in questo caso non ha funzionato. I messaggi di errore che possono essere corretti con questo comando sembrano sempre avere un'istruzione in tal senso, quindi sai come eseguirlo.

Si consiglia, tuttavia, di eseguire systemctl daemon-reload dopo aver modificato un file unit o creato uno nuovo. Questo notifica a systemd che le modifiche sono state apportate e può prevenire alcuni tipi di problemi con la gestione di servizi o unità alterati. Vai avanti ed esegui questo comando.

Dopo aver corretto l'errore di ortografia nel file dell'unità di servizio, un semplice systemctl restart hello.service cancellato l'errore. Sperimenta un po' introducendo altri errori in hello.service file per vedere che tipo di risultati ottieni.

Avvia il servizio

Ora sei pronto per avviare il nuovo servizio e controllare lo stato per vedere il risultato. Anche se probabilmente hai eseguito un riavvio nella sezione precedente, puoi avviare o riavviare un servizio oneshot tutte le volte che vuoi poiché viene eseguito una volta e poi si chiude.

Vai avanti e avvia il servizio (come mostrato di seguito), quindi controlla lo stato. A seconda di quanto hai sperimentato con gli errori, i tuoi risultati potrebbero differire dai miei:

[root@testvm1 ~]# systemctl start hello.service 
[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

Si noti nell'output del comando di stato che i messaggi di sistema indicano che hello.sh script avviato e servizio completato. Puoi anche vedere l'output dello script. Questa visualizzazione è generata dalle registrazioni a giornale delle chiamate più recenti del servizio. Prova ad avviare il servizio più volte, quindi esegui di nuovo il comando status per vedere cosa intendo.

Dovresti anche guardare direttamente i contenuti del diario; ci sono diversi modi per farlo. Un modo consiste nello specificare l'identificatore del tipo di record, in questo caso il nome dello script della shell. Questo mostra le voci del diario per i riavvii precedenti e la sessione corrente. Come puoi vedere, ho cercato e testato questo articolo per un po' di tempo ormai:

[root@testvm1 ~]# journalctl -t hello.sh
<snip>
-- Reboot --
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
May 08 15:55:47 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
May 08 16:01:51 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

Per individuare i record di sistema per hello.service unit, puoi cercare su systemd. Puoi utilizzare G+Invio per andare alla fine delle voci del diario e poi scorrere indietro per individuare quelle che ti interessano. Usa il -b opzione per mostrare solo le voci per l'avvio più recente:

[root@testvm1 ~]# journalctl -b -t systemd
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:50 testvm1.both.org systemd[1]: Starting D-Bus System Message Bus...
May 10 10:37:50 testvm1.both.org systemd[1]: Started D-Bus System Message Bus.

Ho copiato alcune altre voci del diario per darti un'idea di cosa potresti trovare. Questo comando sputa tutte le righe del diario relative a systemd:109.183 righe quando l'ho scritto. Ci sono molti dati da ordinare. Puoi utilizzare la funzione di ricerca del cercapersone, che di solito è less oppure puoi utilizzare il grep integrato caratteristica. Il -g (o --grep= ) utilizza espressioni regolari compatibili con Perl:

[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:01:01 EDT. --
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

Potresti usare lo standard GNU grep comando, ma ciò non mostrerebbe i metadati del registro nella prima riga.

Se non vuoi vedere solo le voci del diario relative al tuo hello servizio, puoi restringere un po' le cose specificando un intervallo di tempo. Ad esempio, inizierò con l'ora di inizio di 10:54:00 sulla mia macchina virtuale di prova, che era l'inizio del minuto da cui provengono le voci sopra. Nota che il --since= l'opzione deve essere racchiusa tra virgolette e che questa opzione può anche essere espressa come -S "<time specification>" .

La data e l'ora saranno diverse sul tuo host, quindi assicurati di utilizzare i timestamp che corrispondono alle ore nei tuoi diari:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:00"
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=54 op=LOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd"'
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/"'
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <error> [1589122560.0633] dhcp4 (enp0s3): error -113 dispatching events
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <info>  [1589122560.0634] dhcp4 (enp0s3): state changed bound -> fail
<snip>

Il since la specifica salta tutte le voci prima di quel momento, ma ci sono ancora molte voci dopo quel periodo di cui non hai bisogno. Puoi anche usare il until opzione per tagliare le voci che arrivano un po' dopo il tempo che ti interessa. Voglio l'intero minuto in cui si è verificato l'evento e nient'altro:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:04:59 EDT. --
May 10 10:54:35 testvm1.both.org systemd[1]: Reloading.
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=27 op=UNLOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=26 op=UNLOAD
<snip>
ay 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
lines 1-46/46 (END)

Se c'è stata molta attività in questo periodo di tempo, potresti restringere ulteriormente il flusso di dati risultante utilizzando una combinazione di queste opzioni:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00" -t "hello.sh"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:10:41 EDT. --
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

I tuoi risultati dovrebbero essere simili ai miei. Puoi vedere da questa serie di esperimenti che il servizio è stato eseguito correttamente.

Riavvia, finalmente

Finora, non hai riavviato l'host su cui hai installato il servizio. Quindi fallo ora perché, dopo tutto, questo how-to riguarda l'esecuzione di un programma all'avvio. Innanzitutto, devi abilitare l'avvio del servizio durante la sequenza di avvio:

[root@testvm1 ~]# systemctl enable hello.service 
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
[root@testvm1 ~]#

Si noti che il collegamento è stato creato in /etc/systemd/system/multi-user.target.wants directory. Questo perché il file dell'unità di servizio specifica che il servizio è "ricercato" da multi-user.target .

Riavvia e assicurati di guardare il flusso di dati durante la sequenza di avvio per visualizzare il messaggio "Hello world". Aspetta... non l'hai visto? Bene, nemmeno io. Sebbene sia passato molto velocemente, ho visto il messaggio di systemd che stava avviando il hello.service .

Guarda il diario dall'ultimo avvio del sistema. Puoi usare il less strumento di ricerca del cercapersone per trovare "Ciao" o "Ciao". Ho eliminato molte righe di dati, ma ho lasciato alcune delle voci di diario circostanti, in modo che tu possa avere un'idea dell'aspetto locale delle voci relative al tuo servizio:

[root@testvm1 ~]# journalctl -b
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Listening on SSSD Kerberos Cache Manager responder socket.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Sockets.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Basic System.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Modem Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Network Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Avahi mDNS/DNS-SD Stack...
May 10 10:37:49 testvm1.both.org systemd[1]: Condition check resulted in Secure Boot DBX (blacklist) updater being skipped.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
May 10 10:37:49 testvm1.both.org systemd[1]: Started irqbalance daemon.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=irqbalance comm="systemd" exe="/usr/lib/sy>"'
May 10 10:37:49 testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Hardware Monitoring Sensors...
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting NTP client/server...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=livesys-late comm="systemd" exe="/usr/lib/>"'
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>"'
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
May 10 10:37:50 testvm1.both.org audit: BPF prog-id=28 op=LOAD
<snip>

Puoi vedere che systemd ha avviato hello.service unit, che eseguiva hello.sh script di shell con l'output registrato nel journal. Se fossi riuscito a catturarlo durante l'avvio, avresti visto anche il messaggio systemd che indicava che stava avviando lo script e un altro messaggio che indicava che il servizio è riuscito. Osservando il primo messaggio systemd nel flusso di dati sopra, puoi vedere che systemd ha avviato il tuo servizio molto presto dopo aver raggiunto la destinazione del sistema di base.

Ma vorrei vedere anche il messaggio visualizzato all'avvio. C'è un modo per farlo accadere:aggiungi la seguente riga a [Service] sezione del hello.service file:

StandardOutput=journal+console

Il hello.service il file ora appare così:

# Simple service unit file to use for testing 
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh
StandardOutput=journal+console

[Install]
WantedBy=multi-user.target

Dopo aver aggiunto questa riga, riavviare il sistema e guardare il flusso di dati mentre scorre il display durante il processo di avvio. Dovresti vedere il messaggio nella sua piccola scatola. Al termine della sequenza di avvio, puoi visualizzare il diario per l'avvio più recente e individuare le voci per il tuo nuovo servizio.

Cambiare la sequenza

Ora che il tuo servizio funziona, puoi guardare da dove inizia nella sequenza di avvio e provare a modificarlo. È importante ricordare che l'intento di systemd è avviare il maggior numero di servizi e altri tipi di unità in parallelo all'interno di ciascuno dei principali target:basic.target , multi-user.target e graphical.target . Dovresti aver appena visto le voci del diario per l'avvio più recente, che dovrebbe essere simile al mio diario nell'output sopra.

Si noti che systemd ha avviato il servizio di test subito dopo aver raggiunto il sistema di base di destinazione. Questo è ciò che hai specificato nel file dell'unità di servizio in WantedBy riga, quindi è corretto. Prima di modificare qualsiasi cosa, elenca i contenuti di /etc/systemd/system/multi-user.target.wants directory e vedrai un collegamento simbolico (soft) al file dell'unità di servizio. Il [Install] la sezione del file dell'unità di servizio specifica quale destinazione avvierà il servizio e l'esecuzione di systemctl enable hello.service il comando crea il collegamento nella directory appropriata "target want" :

hello.service -> /etc/systemd/system/hello.service

Alcuni servizi devono essere avviati durante il basic.target e altri non devono essere avviati a meno che il sistema non avvii graphical.target . Il servizio in questo esperimento non verrà avviato nel basic.target —supponi che non ti serva per iniziare fino a graphical.target . Quindi cambia il WantedBy riga:

WantedBy=graphical.target

Assicurati di disabilitare hello.service e riabilitalo per eliminare il vecchio link e aggiungere il nuovo nel graphical.targets.wants directory. Ho notato che se dimentico di disabilitare il servizio prima di cambiare la destinazione che lo desidera, posso eseguire systemctl disable comando e i collegamenti verranno rimossi da entrambe le directory "target want". Quindi, devo solo riattivare il servizio e riavviare.

Una preoccupazione con l'avvio di servizi in graphical.target è che se l'host si avvia su multi-user.target , questo servizio non si avvierà automaticamente. Potrebbe essere quello che vuoi se il servizio richiede un'interfaccia desktop GUI, ma potrebbe anche non essere quello che vuoi.

Osserva le voci del diario per graphical.target e il multi-user.target usando -o short-monotonic opzione che mostra i secondi dopo l'avvio del kernel con una precisione di microsecondi:

[root@testvm1 ~]# journalctl -b -o short-monotonic

Alcuni risultati per multi-user.target :

[   17.264730] testvm1.both.org systemd[1]: Starting My hello shell script...
[   17.265561] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<SNIP>
[   19.478468] testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
[   19.507359] testvm1.both.org iptables.init[844]: iptables: Applying firewall rules: [  OK  ]
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
[   19.507835] testvm1.both.org hello.sh[843]: ######### Hello World! ########
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
<SNIP>
[   21.482481] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   21.482550] testvm1.both.org smartd[856]: Opened configuration file /etc/smartmontools/smartd.conf
[   21.482605] testvm1.both.org systemd[1]: Finished My hello shell script.

E alcuni risultati per graphical.target :

[   19.436815] testvm1.both.org systemd[1]: Starting My hello shell script...
[   19.437070] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<SNIP>
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.612614] testvm1.both.org hello.sh[841]: ######### Hello World! ########
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.629455] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629569] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629682] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   19.629782] testvm1.both.org systemd[1]: Finished My hello shell script.

Nonostante abbia il graphical.target "want" nel file unit, il hello.service l'unità funziona per circa 19,5 o 19,6 secondi all'avvio. Ma hello.service inizia a circa 17,24 secondi nel multi-user.target e 19,43 secondi nel target grafico.

Cosa significa questo? Guarda il /etc/systemd/system/default.target collegamento. Il contenuto di quel file mostra che systemd avvia prima la destinazione predefinita, graphical.target , che quindi estrae il multi-user.target :

[root@testvm1 system]# cat default.target
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
[root@testvm1 system]#

Se avvia il servizio con graphical.target o il multi-user.target , il hello.service l'unità funziona a circa 19,5 o 19,6 secondi dall'avvio. Sulla base di questo e dei risultati del diario (soprattutto quelli che utilizzano l'output monotono), sai che entrambi questi obiettivi iniziano in parallelo. Guarda un'altra cosa dall'output del diario:

[   28.397330] testvm1.both.org systemd[1]: Reached target Multi-User System.
[   28.397431] testvm1.both.org systemd[1]: Reached target Graphical Interface.

Entrambi i bersagli finiscono quasi contemporaneamente. Ciò è coerente perché graphical.target estrae il multi-user.target e non può terminare fino al multi.user target è raggiunto, cioè finito. Ma  hello.service finisce molto prima di questo.

Tutto ciò significa che questi due obiettivi iniziano praticamente in parallelo. Se esplori le voci del diario, vedrai vari obiettivi e servizi da ciascuno di questi obiettivi primari che iniziano per lo più in parallelo. È chiaro che il multi-user.target non è necessario completare prima di graphical.target inizia. Pertanto, il semplice utilizzo di questi target primari per mettere in sequenza l'avvio non funziona molto bene, sebbene possa essere utile per garantire che le unità vengano avviate solo quando sono necessarie per graphical.target .

Prima di continuare, ripristina hello.service file unit in WantedBy=multi-user.target (se non lo è già.)

Assicurati che un servizio venga avviato dopo che la rete è in esecuzione

Un problema comune relativo alla sequenza di avvio è garantire che un'unità si avvii dopo che la rete è attiva e funzionante. L'articolo di Freedesktop.org Esecuzione dei servizi dopo che la rete è attiva dice che non c'è un vero consenso su quando una rete è considerata "attiva". Tuttavia, l'articolo fornisce tre opzioni e quella che soddisfa le esigenze di una rete completamente operativa è network-online.target . Tieni presente che network.target viene utilizzato durante l'arresto anziché l'avvio, quindi non ti servirà a nulla quando provi a mettere in sequenza l'avvio.

Prima di apportare altre modifiche, assicurati di esaminare il journal e verificare che hello.service l'unità si avvia molto prima della rete. Puoi cercare il network-online.target nel diario da controllare.

Il tuo servizio non richiede realmente il servizio di rete, ma puoi usarlo come avatar per uno che lo richiede.

Perché impostando WantedBy=graphical.target non garantisce che il servizio venga avviato dopo che la rete è attiva e funzionante, è necessario un altro modo per assicurarsi che lo sia. Fortunately, there is an easy way to do this. Add the following two lines to the [Unit] section of the hello.service unit file:

After=network-online.target                                                                             
Wants=network-online.target

Both of these entries are required to make this work. Reboot the host and look for the location of entries for your service in the journals:

[   26.083121] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0293] device (enp0s3): Activation: successful, device activated.
[   26.083349] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0301] manager: NetworkManager state is now CONNECTED_GLOBAL
[   26.085818] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0331] manager: startup complete
[   26.089911] testvm1.both.org systemd[1]: Finished Network Manager Wait Online.
[   26.090254] testvm1.both.org systemd[1]: Reached target Network is Online.
[   26.090399] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-wait-online comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? termina>"'
[   26.091991] testvm1.both.org systemd[1]: Starting My hello shell script...
[   26.095864] testvm1.both.org sssd[be[implicit_files]][1007]: Starting up
[   26.290539] testvm1.both.org systemd[1]: Condition check resulted in Login and scanning of iSCSI devices being skipped.
[   26.291075] testvm1.both.org systemd[1]: Reached target Remote File Systems (Pre).
[   26.291154] testvm1.both.org systemd[1]: Reached target Remote File Systems.
[   26.292671] testvm1.both.org systemd[1]: Starting Notify NFS peers of a restart...
[   26.294897] testvm1.both.org systemd[1]: iscsi.service: Unit cannot be reloaded because it is inactive.
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.304682] testvm1.both.org hello.sh[1010]: ######### Hello World! ########
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.306569] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306669] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306772] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   26.306862] testvm1.both.org systemd[1]: Finished My hello shell script.
[   26.584966] testvm1.both.org sm-notify[1011]: Version 2.4.3 starting

This confirms that the hello.service unit started after the network-online.target . This is exactly what you want. You may also have seen the "Hello World" message as it passed by during startup. Notice also that the timestamp is about six seconds later in the startup than it was before.

The best way to define the start sequence

This article explored Linux startup with systemd and unit files and journals in greater detail and discovered what happens when errors are introduced into the service file. As a sysadmin, I find that this type of experimentation helps me understand the behaviors of a program or service when it breaks, and breaking things intentionally is a good way to learn in a safe environment.

As the experiments in this article proved, just adding a service unit to either the multi-user.target or the graphical.target does not define its place in the start sequence. It merely determines whether a unit starts as part of a graphical environment or not. The reality is that the startup targets multi-user.target and graphical.target —and all of their Wants and Requires—start up pretty much in parallel. The best way to ensure that a unit starts in a specific order is to determine the unit it is dependent on and configure the new unit to "Want" and "After" the unit upon which it is dependent.

Risorse

Ci sono molte informazioni su systemd disponibili su Internet, ma molte sono concise, ottuse o addirittura fuorvianti. In addition to the resources mentioned in this article, the following webpages offer more detailed and reliable information about systemd startup.

  • Il progetto Fedora ha una buona guida pratica a systemd. Ha praticamente tutto ciò che devi sapere per configurare, gestire e mantenere un computer Fedora usando systemd.
  • Il progetto Fedora ha anche un buon cheat sheet che incrocia i vecchi comandi SystemV con quelli di systemd comparabili.
  • Per informazioni tecniche dettagliate su systemd e sui motivi della sua creazione, consulta la descrizione di systemd di Freedesktop.org.
  • "Più divertimento di sistema" di Linux.com offre informazioni e suggerimenti più avanzati sul sistema.

C'è anche una serie di articoli profondamente tecnici per gli amministratori di sistema Linux di Lennart Poettering, il designer e sviluppatore principale di systemd. Questi articoli sono stati scritti tra aprile 2010 e settembre 2011, ma sono rilevanti ora come allora. Gran parte di tutto ciò che è stato scritto di buono su systemd e il suo ecosistema si basa su questi documenti.

  • Ripensare il PID 1
  • systemd per amministratori, parte I
  • sistema per amministratori, parte II
  • sistema per amministratori, parte III
  • systemd per amministratori, parte IV
  • sistema per amministratori, parte V
  • sistema per amministratori, parte VI
  • sistema per amministratori, parte VII
  • systemd per amministratori, parte VIII
  • systemd per amministratori, parte IX
  • sistema per amministratori, parte X
  • systemd per amministratori, parte XI

Linux
  1. Utilizzo del comando systemctl per gestire le unità systemd

  2. Come gestire i servizi Systemd con Systemctl su Linux

  3. Sostituzione di rc.local nei sistemi Linux systemd

  4. Come scrivere uno script di avvio per Systemd?

  5. Systemd:utilizzo sia di After che di Requires

Comandi Systemctl per gestire il servizio Systemd

Utilizzo delle funzionalità di systemd per proteggere i servizi

Come utilizzare il comando Systemctl per gestire i servizi Systemd

Come configurare l'esecuzione automatica di uno script Python utilizzando Systemd

Modo corretto di usare Ubuntu systemctl per controllare Systemd

Il file di servizio esiste ma non viene trovato da systemd