Generazione di sistemi e processi


14

Normalmente non postare qui, ma mi sto strappando i capelli sopra questo. Ho uno script Python che esegue il fork all'avvio ed è responsabile dell'avvio di un sacco di altri processi. Questo script veniva lanciato all'avvio tramite sysvinit, ma recentemente ho eseguito l'aggiornamento a Debian Jessie, quindi l'ho adattato per l'avvio tramite systemd.

Sfortunatamente, sto riscontrando un problema che non riesco a risolvere. Quando si avvia lo script direttamente in una shell utente, avvia correttamente i processi figlio e quando lo script esce i processi figlio vengono resi orfani e continuano a essere eseguiti.

Quando viene avviato tramite systemd, se il processo padre termina, anche i bambini escono tutti (beh, lo schermo che si lancia in die e appare come morto ???)

Idealmente, devo essere in grado di riavviare lo script padre senza uccidere tutti i processi figlio, c'è qualcosa che mi manca?

Grazie!

[Unit]
Description=Server commander
After=network.target

[Service]
User=serveruser
Type=forking
PIDFile=/var/Server/Server.pid

ExecStart=/var/Server/Server.py
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

Modifica: è probabilmente rilevante per me sottolineare che lo script Python è essenzialmente un "controller" per i suoi processi figlio. Avvia e arresta i server nelle schermate gnu come richiesto da un server centrale. Normalmente è sempre in esecuzione, non genera servizi e non esce. In alcuni casi, tuttavia, vorrei poter ricaricare lo script senza uccidere i processi figlio, anche se ciò significa che i processi sono resi orfani al pid 1. In realtà, non importa nemmeno se lo script Python ha avviato i processi come un processo genitore, se possibile.

Una migliore spiegazione di come funziona:

  • Systemd spawns /Server.py
  • Server.py esegue il fork e scrive il file pid per Systemd
  • Server.py quindi genera i processi del server nella schermata gnu in base alle sue istruzioni
  • Server.py continua a funzionare per eseguire qualsiasi riavvio richiesto dal server

Quando si avvia senza Systemd, Server.py può essere riavviato e le schermate gnu che avvia non sono interessate. Quando si avvia con Systemd, quando Server.py si arresta, invece di rendere orfani quei processi di schermo al pid 1, vengono uccisi.


1
È difficile fornire una soluzione senza avere il Server.pycodice e una descrizione di come eseguono i fork dei servizi lanciati (se fork). Tuttavia, in generale, si tratta di un problema di mancata corrispondenza del protocollo di disponibilità .
intelfx,

A proposito, ExecStop=non è necessario. L'azione predefinita di systemd all'arresto è l'uccisione dei processi. Potresti dare un'occhiata alla documentazione per KillMode=direttiva.
intelfx,

1
E infine ... Se non esiste un protocollo di prontezza adeguato (uno simpleo forking, in realtà), l'ultima risorsa sarebbe Type=oneshot, RemainAfterExit=yese KillMode=control-group.
intelfx,

@intelfx Essenzialmente lo script Python avvia un server in una schermata usando Subprocess.call. È più complicato di così perché lo script riceve comandi da altrove dicendogli quali schermate avviare e quali no. Le schermate disponibili sono anche dinamiche, quindi perché non possono essere servizi di sistema a sé stanti. Idealmente non voglio che systemd tratti queste schermate come parte del servizio, ma attualmente vengono scaricate nello stesso gruppo di processi e muoiono con il master se viene riavviato.
Bottswana,

La mia impressione è che systemd non "gestisca" un processo di controllo del genere (cerca solo i PID all'inizio, non riconosce quelli successivi ...): |
rogerdpack,

Risposte:


9

Sono riuscito a risolvere questo problema semplicemente impostando KillMode su process anziché su control-group (impostazione predefinita). Ringrazia tutti


Sembra però qualcosa di più di una soluzione, vedi le altre risposte ... se lo fai e fai un "arresto del sistema", non ucciderà i processi figlio che eseguiranno comunque [?] al di fuori della supervisione di systemctl?
rogerdpack,

5

Ho uno script Python che esegue il fork all'avvio ed è responsabile dell'avvio di un sacco di altri processi.

Il che indica che lo stai facendo in modo errato. Altro in questo in un momento.

quando lo script esce, i processi figlio sono orfani e continuano a essere eseguiti.

Questo non è un comportamento corretto. Se il processo "principale" - in questo caso il figlio che hai biforcato, come hai specificato Type=forking- esce, systemd considera il servizio disattivato e termina qualsiasi altro processo ancora in esecuzione (nel gruppo di controllo) per riordinare .

A volte la conversione dagli rcscript di System 5 a systemd non è semplice, perché il modo giusto di fare le cose con systemd è abbastanza diverso. Il modo giusto di fare (diciamo) OpenVPN, OpenStack o OSSEC HIDS in systemd non è lo stesso che si farebbe con uno rcscript. Il fatto che tu abbia una sceneggiatura che sta biforcando, quindi generando un intero carico di processi di nipoti, quindi uscendo aspettandoti che quei nipoti continuino a correre indica che stai perpetrando lo stesso tipo di orrore di ossec-control, sebbene con due livelli di biforcazione in meno. Se ti ritrovi a scrivere uno script "master" che controlla "abilita" i flag ed esegue i processi figlio per le parti "abilitate" del tuo sistema, allora stai facendo lo stesso errore dell'orrendo ossec-control.

Con systemd non sono necessari tali meccanismi di coltivazione interna. È già un service manager. Per /unix//a/200365/5132 , il modo giusto per farlo in systemd non è di avere un servizio che genera un tentativo stravagante e confuso di avere "sotto-servizi". Deve avere ogni processo figlio come un servizio di sistema completo a tutti gli effetti. Quindi si abilita e disabilita, e avvia e arresta, le varie parti del sistema usando i normali controlli di sistema. Come puoi vedere nel caso OSSEC HIDS, una semplice unità di servizio modello copre quasi tutti i servizi (un'eccezione è su /ubuntu//a/624871/43344 ), consentendo di fare cose come systemctl enable ossec@agentlessd.serviceabilitare un facoltativoagentlessdservizio, senza alcun bisogno dell'orrendo meccanismo "master script" necessario con System 5 rc.

Ci sono molti casi, forse non così estremi come OSSEC HIDS, in cui è necessario un ripensamento. MTS come exim e sendmail sono due di questi. Si potrebbe aver avuto un singolo rcscript che genera un runner di coda, un progetto di invio SMTP e un modulo di inoltro SMTP, con un gruppo di variabili shell ad hoc in un file di configurazione per controllare esattamente quali vengono eseguite. Ma il modo giusto per farlo con systemd è di avere tre unità di servizio appropriate (due delle quali hanno unità socket associate ) e nessuna roba ad hoc, solo i normali meccanismi del gestore del servizio.


Apprezzo il feedback su questo. Anche se concordo sul fatto che avere servizi di sottoinsieme abbia un senso, è stato fatto in Python per un motivo che non posso approfondire. La mia unica soluzione è trovare un modo per far funzionare questo metodo. Grazie comunque. Mi piacerebbe farlo correttamente.
Bottswana,

I sottoservizi avviati dallo script sono solo server in esecuzione nella schermata gnu come utente specifico. Questi server cambiano molto, alcuni vengono aggiunti, alcuni vengono rimossi e questo è controllato altrove, quindi non possono essere realmente servizi reali in systemd, perché ciò aggiunge molta complessità e non può essere gestito centralmente. Inoltre, lo stesso script viene utilizzato anche su server non systemd.
Bottswana,

systemd dispone di funzionalità esplicite per consentire l'aggiunta e la rimozione di servizi senza la necessità di accedere alla radice. Il "utilizzato anche su servizi non di sistema" è l'unico degli argomenti sopra che non può essere risolto aggiungendo altro systemd ... beh, probabilmente, anche quello potrebbe esserlo. :)
Charles Duffy,

0

Potresti semplicemente dormire il genitore e attendere che systemd lo uccida al momento della sospensione.

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.