Sto scrivendo systemd
file unit per OSSEC HIDS. Il problema è che quando systemd
avvia i servizi li interrompe immediatamente.
Quando utilizzo il seguente ExecStart
direttiva funziona tutto bene.
ExecStart=/var/ossec/bin/ossec-control start
Ma quando faccio questo dopo un piccolo miglioramento, trovo nei registri OSSEC che riceve SIG 15
dopo l'inizio.
ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'
Se apporto un'altra piccola modifica, il servizio riceverà SIG 15
dopo 20 secondi.
ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'
Quindi, suppongo, quel systemd
uccide /bin/sh
processo dopo l'avvio del servizio e /bin/sh
quindi uccide OSSEC
.
Come posso risolvere questo problema?
Risposta accettata:
Mancata corrispondenza del protocollo di preparazione
Come suggerisce Wieland, il Type
del servizio è importante. Questa impostazione indica quale protocollo di preparazione systemd si aspetta che il servizio parli. Un simple
si presume che il servizio sia immediatamente pronto. Un forking
il servizio viene considerato pronto dopo che il suo processo iniziale esegue il fork di un figlio e quindi esce. Un dbus
il servizio viene considerato pronto quando un server viene visualizzato sul bus desktop. E così via.
Se non ottieni il protocollo di prontezza dichiarato nell'unità di servizio in modo che corrisponda a ciò che fa il servizio, le cose vanno storte. Le mancate corrispondenze del protocollo di disponibilità fanno sì che i servizi non vengano avviati correttamente o (più in genere) vengano diagnosticati (erroneamente) da systemd come guasti. Quando si ritiene che un servizio non si avvii systemd assicura che ogni processo aggiuntivo orfano del servizio che potrebbe essere stato lasciato in esecuzione come parte dell'errore (dal suo punto di vista) viene interrotto per riportare correttamente il servizio allo stato inattivo.
Stai facendo esattamente questo.
Prima di tutto, le cose semplici:sh -c
non corrisponde a Type=simple
o Type=forking
.
Nel simple
protocollo, il processo iniziale viene considerato essere il processo di servizio. Ma in effetti un sh -c
wrapper esegue il programma di servizio effettivo come processo figlio . Quindi MAINPID
va storto e ExecReload
smette di funzionare, tanto per cominciare. Quando si utilizza Type=simple
, è necessario utilizzare sh -c 'exec …'
o non utilizzare sh -c
innanzitutto. Quest'ultimo è più spesso il corso corretto di quanto alcune persone pensino.
sh -c
non corrisponde a Type=forking
o. Il protocollo di prontezza per un forking
il servizio è abbastanza specifico. Il processo iniziale deve biforcare un figlio e quindi uscire. systemd applica un timeout a questo protocollo. Se il processo iniziale non si biforca entro il tempo assegnato, è un fallimento nel diventare pronto. Se il processo iniziale non termina entro il tempo assegnato, anche questo è un fallimento.
l'orrore non necessario che è ossec-control
Il che ci porta alle cose complesse:quel ossec-control
copione.
Si scopre che è un rc
di System 5 script che biforca tra 4 e 10 processi, che a loro volta si biforcano ed escono anch'essi. È uno di quei rc
di System 5 script che tenta di gestire un intero set di processi server in un unico script, con for
loop, condizioni di gara, sleep
arbitrario s per cercare di evitarli, modalità di errore che possono soffocare il sistema in uno stato semi-avviato e tutti gli altri orrori che hanno portato le persone a inventare cose come AIX System Resource Controller e daemontools due decenni fa. E non dimentichiamo lo script di shell nascosto in una directory binaria che riscrive al volo, per implementare l'idiosincratico enable
e disable
verbi.
Quindi, quando /bin/sh -c '/var/ossec/bin/ossec-control start'
quello che succede è che:
- systemd esegue il fork di quello che si aspetta essere il processo di servizio.
- Questa è la shell, che esegue il fork di
ossec-control
. - Che a sua volta biforca tra 4 e 10 nipoti.
- I nipoti si biforcano ed escono a turno.
- I pronipoti si biforcano ed escono tutti in parallelo.
ossec-control
esce.- La prima shell esce.
- I processi di servizio erano il bis-bis- nipoti, ma perché questo modo di lavorare non corrisponde a né il
forking
né ilsimple
readiness protocol, systemd considera il servizio nel suo insieme non riuscito e lo chiude nuovamente.
Niente di tutto questo orrore è effettivamente necessario sotto systemd. Niente di tutto questo.
un'unità di servizio modello systemd
Invece, si scrive un'unità modello molto semplice :
[Unit] Description=The OSSEC HIDS %i server After=network.target [Service] Type=simple ExecStartPre=/usr/bin/env /var/ossec/bin/%p-%i -t ExecStart=/usr/bin/env /var/ossec/bin/%p-%i -f [Install] WantedBy=multi-user.target
Salvalo come /etc/systemd/system/[email protected]
.
I vari servizi effettivi sono istanziazioni di questo modello, denominato:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
Quindi abilitare e disabilitare la funzione proviene direttamente dal sistema di gestione del servizio (con il bug di RedHat 752774 corretto), senza bisogno di script di shell nascosti.
systemctl enable [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
Inoltre, systemd viene a conoscenza e traccia direttamente ogni servizio effettivo. Può filtrare i loro registri con journalctl -u
. Può sapere quando un singolo servizio ha fallito. Sa quali servizi dovrebbero essere abilitati e in esecuzione.
A proposito:Type=simple
e il -f
opzione sono proprio qui come lo sono in molti altri casi. Pochissimi servizi in natura segnalano effettivamente la loro disponibilità a forza di exit
, e anche questi qui non sono casi del genere. Ma questo è ciò che il forking
tipo significa. I servizi in natura nella principale si biforcano ed escono a causa di un'idea errata ricevuta che è ciò che dovrebbero fare i daimon. In effetti, non lo è. Non è più dagli anni '90. È ora di recuperare il ritardo.
Ulteriori letture
- Jonathan de Boyne Pollard (2015). Problemi di prontezza del protocollo con i demoni Unix . Risposte frequenti.