Come può un servizio systemd contrassegnare che è pronto, in modo che altri servizi possano attendere che sia pronto prima di iniziare?


8

Ho un sacco di servizi (diciamo C0, C1... C9) che dovrebbero iniziare solo dopo che un servizio Sha completato la sua inizializzazione ed è completamente in esecuzione e pronto per gli altri servizi. Come lo organizzo con systemd?

Nei servizi di ordinazione con attivazione percorso e destinazione in systemd , si presume che il servizio Sabbia un meccanismo per scrivere una sorta di file flag. Supponiamo qui, al contrario, che io abbia il pieno controllo sul programma che il servizio Sviene eseguito e, se necessario, posso aggiungere al suo interno meccanismi di sistema.

Risposte:


7

Uno non ha necessariamente bisogno di questo.

Se i Cservizi devono attendere per Sessere pronti in modo che possano aprire una connessione socket ad esso, allora non è necessario farlo affatto. Piuttosto, si può trarre vantaggio dall'apertura anticipata della presa di ascolto da parte dei gestori dei servizi.

Diversi sistemi, tra cui il s6 di Laurent Bercot , il mio set di strumenti nosh e systemd, hanno dei modi in cui una presa di ascolto può essere aperta in anticipo, la prima cosa da fare per impostare il servizio. Tutti implicano qualcosa di diverso dal programma di servizio che apre i socket di ascolto e il programma di servizio, quando viene invocato, riceve i socket di ascolto come descrittori di file già aperti.

Con systemd, in particolare, si crea un'unità socket che definisce la presa di ascolto. systemd apre l'unità socket e la configura in modo che il sottosistema di rete del kernel ascolti le connessioni; e lo passa al servizio effettivo come descrittore di file aperto quando si tratta di spawn i processi che gestiscono le connessioni al socket. (Può farlo in due modi, proprio come inetdpotrebbe, ma una discussione sui dettagli Accept=truerispetto ai Accept=falseservizi va oltre lo scopo di questa risposta.)

Il punto importante è che non è necessario necessariamente più ordinamento di quello. Il kernel raggruppa le connessioni client in una coda fino a quando il programma di servizio non viene inizializzato e pronto ad accettarle e parlare con i client.

Quando si fa, i protocolli di prontezza sono la cosa.

systemd ha una serie di protocolli di prontezza che comprende, servizio specificato per servizio con l' Type=impostazione nell'unità di servizio. Il protocollo di prontezza particolare di interesse qui è il notifyprotocollo di prontezza. Con esso, viene richiesto a systemd di aspettarsi messaggi dal servizio e quando il servizio è pronto, invia un messaggio che segnala la disponibilità. systemd ritarda l'attivazione degli altri servizi fino a quando la disponibilità non viene contrassegnata.

Fare uso di questo implica due cose:

  • Modifica del codice in Smodo che chiami qualcosa come la funzione di Pierre-Yves Ritschard notify_systemd()o la funzione di Cameron T. Norman notify_socket().
  • Impostazione dell'unità di servizio per il servizio con Type=notifye NotifyAccess=main.

La NotifyAccess=mainrestrizione (che è l'impostazione predefinita) è perché systemd deve sapere di ignorare i messaggi provenienti da programmi maliziosi (o semplicemente difettosi), poiché qualsiasi processo sul sistema può inviare messaggi al socket di notifica di systemd.

Uno usa il codice di Pierre-Yves Ritschard o Cameron T. Norman come preferenza perché non esclude la possibilità di avere questo meccanismo su UbuntuBSD, Debian FreeBSD, FreeBSD attuale, TrueOS, OpenBSD e così via; che il codice fornito dagli autori di systemd esclude.

Una trappola da evitare è il systemd-notifyprogramma. Ha diversi problemi importanti, non ultimo il fatto che i messaggi inviati con esso possono finire per essere eliminati non elaborati da systemd. Il problema più importante in questo caso è che non funziona come il processo "principale" del servizio, quindi è necessario aprire le notifiche di disponibilità per il servizio Sa ogni processo sul sistema con NotifyAccess=all.

Un'altra trappola da evitare è pensare che il forkingprotocollo sia più semplice. Non è. Farlo correttamente implica non biforcarsi ed uscire dal genitore fino a quando (per prima cosa) tutti i thread di lavoro del programma sono in esecuzione. Questo non corrisponde a come la stragrande maggioranza dei demoni che si biforcano effettivamente biforcano.

Ulteriori letture


1
Secondo l'uomo systemd.service(5), NotifyAccess=allaccetterà i messaggi di tutti i membri del gruppo di controllo del servizio , il che non implica solo alcun processo canaglia sul sistema. Questo è abbastanza sicuro per la maggior parte dei casi d'uso. Inoltre, la tua preoccupazione per la portabilità ad altri sistemi operativi non è rilevante per OP, poiché qui siamo già sull'argomento Systemd.
Amir

1

Facendo riferimento alla pagina del manuale systemd.service(5), in particolare alla sezione relativa a Type = , ogni tipo di servizio ha un modo diverso per Systemd di determinare che è pronto ad offrire funzionalità ad altri servizi:

  • Se Type=simple, i suoi canali di comunicazione dovrebbero essere installati prima dell'avvio del demone (ad es. Socket impostati da systemd, tramite l'attivazione socket).

  • Se Type=forking, il processo padre dovrebbe terminare quando l'avvio è completo e tutti i canali di comunicazione sono impostati.

  • Se Type=dbus, si prevede che il demone acquisisca un nome sul bus D-Bus, a quel punto systemd procederà all'avvio delle unità di follow-up.

  • Se Type=notify, si prevede che il demone invii un messaggio di notifica tramite sd_notify(3)o una chiamata equivalente al termine dell'avvio. systemd procederà all'avvio delle unità di follow-up dopo l'invio di questo messaggio di notifica.

Per l'ultima opzione (invio di un messaggio tramite sd_notify), è possibile utilizzare l' systemd-notifyutilità e ricordare di concedergli l'accesso NotifyAccess=all.

Dato che hai il controllo del servizio S, sei libero di scegliere l'opzione migliore per il tuo caso d'uso, o semplicemente quella più facile da implementare.


1

come questo:

S.service

[Unit]
Description=My main Service

[Service]
Type=notify
ExecStart=/usr/bin/myBinary

C0.service

[Unit]
Description=Dependent service number 0
PartOf=S.service

C1.service

[Unit]
Description=Dependent service number 1
PartOf=S.service

C9.service

[Unit]
Description=Dependent service number 9
PartOf=S.service

Dove / usr / bin / myBinary effettua una chiamata sd_notify READY = 1 al termine dell'inizializzazione.

A seconda di come si desidera che la dipendenza si comporti, è possibile utilizzare PartOf, Requis o BindsTo o altri .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.