J'écris le fichier d'unité systemd pour OSSEC HIDS. Le problème est que lorsque systemd démarre le service, il les arrête immédiatement.
Lorsque j'utilise cette directive ExecStart, tout fonctionne bien.
ExecStart=/var/ossec/bin/ossec-control start
Mais quand je fais une petite amélioration, je suis bien dans les journaux OSSEC, qu'il reçoive SIG 15 après le démarrage.
ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'
Si je fais un autre petit changement, le service recevra SIG 15 après 20 secondes.
ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'
Donc, je suppose, que systemd tue / bin / sh après le démarrage du service, et bin / sh tue alors OSSEC.
Comment puis-je résoudre ce problème?
Réponses:
incompatibilité du protocole de préparation
Comme Wieland l'a laissé entendre,
Type
le service est important. Ce paramètre indique quel protocole de préparation systemd attend du service qu'il parle. Unsimple
service est supposé être immédiatement prêt. Unforking
service est censé être prêt après que son processus initial a forcé un enfant puis se termine. Undbus
service est considéré comme prêt lorsqu'un serveur apparaît sur le bus de bureau. Et ainsi de suite.Si vous n'obtenez pas le protocole de disponibilité déclarée dans l'unité de service pour correspondre à ce que fait le service, alors les choses tournent mal. L'inadéquation des protocoles de disponibilité empêche les services de démarrer correctement ou (plus généralement) d'être (mal) diagnostiqués par systemd comme défaillants. Lorsqu'un service est considéré comme ne démarrant pas systemd, il garantit que tous les processus supplémentaires orphelins du service qui pourraient avoir été laissés en cours d'exécution dans le cadre de l'échec (de son point de vue) sont tués afin de ramener correctement le service à l'inactif. Etat.
Tu fais exactement ça.
Tout d'abord, le truc simple:
sh -c
ne correspond pasType=simple
ouType=forking
.Dans le
simple
protocole, le processus initial est considéré comme le processus de service. Mais en fait, unsh -c
wrapper exécute le programme de service réel en tant que processus enfant . Va doncMAINPID
mal etExecReload
cesse de fonctionner, pour commencer. Lors de l'utilisationType=simple
, il faut utilisersh -c 'exec …'
ou ne pas utilisersh -c
en premier lieu. Ce dernier est plus souvent le bon choix que certains ne le pensent.sh -c
ne correspond pas nonType=forking
plus. Le protocole de préparation d'unforking
service est assez spécifique. Le processus initial doit bifurquer un enfant, puis quitter. systemd applique un délai d'attente à ce protocole. Si le processus initial ne se déroule pas dans le temps imparti, c'est un échec à devenir prêt. Si le processus initial ne se termine pas dans le temps imparti, c'est aussi un échec.l'horreur inutile qui est
ossec-control
Ce qui nous amène au truc complexe: ce
ossec-control
script.Il s'avère que c'est un
rc
script System 5 qui bifurque entre 4 et 10 processus, qui eux-mêmes à leur tour bifurquent et sortent également. C'est l'un de cesrc
scripts System 5 qui tente de gérer tout un ensemble de processus serveur dans un seul script, avec desfor
boucles, des conditions de concurrence, des arbitrairessleep
pour essayer de les éviter, des modes de défaillance qui peuvent étouffer le système dans un état semi-démarré, et toutes les autres horreurs qui ont poussé les gens à inventer des choses comme AIX System Resource Controller et daemontools il y a deux décennies. Et n'oublions pas le script shell caché dans un répertoire binaire qu'il réécrit à la volée, pour implémenter idiosyncrasiquesenable
etdisable
verbes.Donc, quand vous
/bin/sh -c '/var/ossec/bin/ossec-control start'
ce qui se passe, c'est que:ossec-control
.ossec-control
sort.forking
ni ausimple
protocole de préparation, systemd considère que le service dans son ensemble a échoué et le ferme.Aucune de ces horreurs n'est réellement nécessaire sous systemd. Rien de cela.
une unité de service de modèle systemd
Au lieu de cela, on écrit une unité de modèle très simple :
Enregistrez ceci sous
/etc/systemd/system/[email protected]
.Les différents services réels sont des instanciations de ce modèle, nommé:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
Ensuite, la fonction d'activation et de désactivation vient directement du système de gestion des services (avec le bogue RedHat 752774 corrigé), sans avoir besoin de scripts shell cachés.
De plus, systemd apprend à connaître et à suivre directement chaque service réel. Il peut filtrer leurs journaux avec
journalctl -u
. Il peut savoir lorsqu'un service individuel a échoué. Il sait quels services sont censés être activés et en cours d'exécution.Soit dit en passant:
Type=simple
et l'-f
option est aussi juste ici que dans de nombreux autres cas. Très peu de services dans la nature signalent en fait leur disponibilité à force de celaexit
, et ce ne sont pas de tels cas ici non plus. Mais c'est ce que leforking
type signifie. Les services à l'état sauvage dans la fourchette principale et la sortie principale en raison d'une notion de sagesse reçue erronée selon laquelle c'est ce que les démons sont censés faire. En fait, ce n'est pas le cas. Cela ne s'est pas produit depuis les années 1990. Il est temps de se rattraper.Lectures complémentaires
la source
Requires=
toutes les instances nécessaires, puis de définirPartOf=ossec.target
dans ossec @ .service. Cela permettra de démarrer et d'arrêter ossec en démarrant et en arrêtant ossec.target.Gardez Type = forking et donnez un emplacement de fichier pid si le service / l'application de démarrage maintient un pid.
[Unité]
Description = "Exécuter l'application au démarrage"
Après = network.target syslog.target auditd.service
[Service]
Type = forking
PIDFile = / var / run / apache2 / apache2.pid
ExecStart = / etc / init.d / apache2 start
ExecStop = / etc / init.d / apache2 stop
StandardOutput = syslog
StandardError = syslog
Restart = on-failure
SyslogIdentifier = webappslog
[Install]
WantedBy = multi-user.target
Alias = webapps
la source
Quelque peu lié, j'avais un service systemd qui semblait que systemd le "tuerait" après 30s.
systemctl status service-name
montreraitmain process exited, code=exited, status=1/FAILURE
après que 30s se soient écoulés.Il fonctionnerait bien "de manière isolée" (comme manuellement dans le terminal avec le même environnement ).
Il s'avère que c'était
à l'intérieur,
my_script_to_spawn_process.sh
il faisait/bin/something > /dev/null 2>&1 &
qui fonctionne mais supprimait les informations du journal de sortie (normalement, il va dans un fichier, ou sinon, peut-être
journalctl
).Le changer pour se connecter à un autre endroit comme
/bin/something > /tmp/my_file
puis suivre la
/tmp/my_file
cause réelle révélée. Ce qui était (tangentiellement) que vous ne pouvez pas utiliser la syntaxeEnvironment=ABC="true"
comme vous pouvez le faire dans bash, il ne doit pas y avoir de guillemets ou la valeur clé dans les guillemets commeEnvironment="ABC=true"
ce qui faisait que mon processus se terminait "dans sa phase de configuration" après environ 30s.la source
Notez que le modèle de démon de systemd est simpliste et incompatible avec de nombreux démons existants qui font de multiples forks, exec'ing et setuid'ing. Les plus courants sont les démons qui commencent en tant que root pour configurer les choses, puis basculent vers un UID moins privilégié pour les opérations de routine. Par exemple, l'initialisation du fichier Pid est une chose qui échoue sous systemd en raison de problèmes de privilèges. Il existe des solutions de contournement (pas de correctifs) mais elles sont mal documentées.
L'explication de JdeBP est la bienvenue mais incomplète et son affirmation selon laquelle tout est la faute d'Ossec-Control n'est tout simplement pas vraie. Même des choses assez banales sont problématiques, par exemple obtenir des lignes de journal non tronquées pour déboguer des problèmes ou des messages d'erreur significatifs de systemd lui-même quand il tue des processus.
la source