Pourquoi «le processus ne doit pas bifurquer» pour les services de type simple dans systemd?

Aug 15 2020

Je veux écrire mes propres systemdfichiers unitaires pour gérer les commandes très longues 1 (dans l'ordre des heures). En regardant l' article ArchWiki sur systemd , il dit ce qui suit concernant le choix d'un type de démarrage:

Type=simple(par défaut): systemd considère que le service est démarré immédiatement. Le processus ne doit pas bifurquer . N'utilisez pas ce type si d'autres services doivent être commandés sur ce service, sauf s'il est activé par socket.

Pourquoi le processus ne doit-il pas du tout bifurquer? Cela fait-il référence à la fourche dans le style du processus d'invocation du démon (fourche parent, puis sortie), ou à toute sorte de fourchette?


1 Je ne veux pas de tmux / screen parce que je veux un moyen plus élégant de vérifier l'état et de redémarrer le service sans recourir à tmux send-keys.

Réponses

41 Gilles'SO-stopbeingevil' Aug 15 2020 at 17:29

Le service est autorisé à appeler l' forkappel système. Systemd ne l'empêchera pas, ni même le remarquera. Cette phrase se réfère spécifiquement à la pratique de forking au début d'un démon pour isoler le démon de son processus parent. «Le processus ne doit pas bifurquer [et quitter le parent lors de l'exécution du service dans un processus enfant]».

La page de manuel explique cela de manière plus verbeuse et avec un libellé qui n'entraîne pas cette confusion particulière.

De nombreux programmes destinés à être utilisés comme démons ont un mode (souvent le mode par défaut) dans lequel lorsqu'ils démarrent, ils s'isolent de leur parent. Le démon démarre, appelle fork()et le parent se ferme. Le processus enfant appelle setsid()afin qu'il s'exécute dans son propre groupe de processus et session, et exécute le service. Le but est que si le démon est appelé à partir d'une ligne de commande shell, le démon ne recevra aucun signal du noyau ou du shell même si quelque chose arrive au terminal tel que la fermeture du terminal (auquel cas le shell envoie SIGHUP à tous les groupes de processus dont il a connaissance). Cela provoque également l'adoption du processus de maintenance par init, qui le récoltera à sa sortie, évitant un zombie si le démon était démarré par quelque chose qui ne le ferait pas wait()(cela ne se produirait pas si le démon était démarré par un shell ).

Lorsqu'un démon est lancé par un processus de surveillance tel que systemd, le forking est contre-productif. Le processus de surveillance est censé redémarrer le service en cas de panne, il doit donc savoir si le service se termine, et c'est difficile si le service n'est pas un enfant direct du processus de surveillance. Le processus de surveillance n'est pas censé mourir et n'a pas de terminal de contrôle, il n'y a donc pas de soucis concernant les signaux indésirables ou la récolte. Il n'y a donc aucune raison pour que le processus de service ne soit pas un enfant du moniteur, et il y a une bonne raison pour qu'il le soit.

15 JdeBP Aug 16 2020 at 11:59

Ignorez cette page wiki d'Arch.

Il a des choses très mal en ce qui concerne le Typecadre. Cela ne se limite pas seulement à ses descriptions de simple. Ce qu'il dit forkingest également faux.

Les recommandations correctes pour ce genre de choses existent depuis des décennies plus longtemps que systemd lui-même, et remontent au moins au début des années 1990. Comme je l'ai noté àhttps://unix.stackexchange.com/a/476608/5132, dans le doco systemd, il y a une version Johnny-come-lastely des recommandations pour dæmons qui répète largement ce que les utilisateurs de daemontools, IBM, les gens utilisent inittab, et… enfin… je dis depuis des décennies. (C'était déjà une réponse fréquemment donnée lorsque je l'ai rédigée comme telle en 2001.)

Répéter:

Si votre programme a un mécanisme de "démonisation", qui en particulier fourche un enfant et quitte le processus parent, désactivez-le et ne l'utilisez pas . Merci à daemontools et al. là où cela a été une exigence depuis longtemps, de nombreux programmes ont développé la capacité de ne pas avoir de tels mécanismes au cours des 20 dernières années, et d'autres ne sont tout simplement pas par défaut à «démoniser» en premier lieu et peuvent donc être utilisés dans leurs modes de fonctionnement par défaut.

Les sous-systèmes de gestion des services lancent déjà les processus de service dans le contexte dæmon . Ces processus n'ont pas besoin d'être «démonisés». (En effet, c'est une erreur sur de nombreux systèmes d'exploitation modernes de penser que les programmes peuvent même «démoniser» à partir d'un contexte de session de connexion, ce qui est en fait l'objet de la «démonisation».) Ils ont déjà les valeurs d'environnement et ouvrent des descripteurs de fichiers, approprié au contexte de dæmon, et les nombreuses choses faites par la «démonisation» en fait contrecarrent certaines des choses conventionnelles qui sont régulièrement faites avec les dæmons (par exemple, capturer leurs sorties / erreurs standard dans un journal) par les gestionnaires de services.

Préférez Type=simple, avec l'ouverture précoce des sockets (où la gestion des services ouvre les sockets du serveur et les transmet en tant que descripteurs de fichiers déjà ouverts au programme de service), ou Type=notify.

  • Type=simple traite le service comme prêt (afin que les services commandés puissent être démarrés / arrêtés) dès que le processus de service commence, avec l'ouverture précoce de la socket utilisant la sémantique de connexion de socket pour retarder les clients de service, aux points où ils tentent de se connecter aux serveurs pour service, jusqu'à ce que les serveurs soient réellement prêts.
  • Type=notifyprésente l'inconvénient d'être propre à systemd et à Linux (parallèlement aux problèmes de ne pas être fonctionnel à partir de processus de courte durée tels qu'un shell spawning systemd-notify, et d'utiliser l'analyse de formes lisibles par l'homme en formes lisibles par machine dans un processus privilégié des problèmes d'analyseur se sont déjà produits dans le passé) mais a l'avantage de fournir un contrôle plus fin (du point de vue du programme de service) du moment où le service est réellement considéré comme prêt. Il permet également une certaine personnalisation de la sortie d'état.

Les programmes de service, des deux types, peuvent bifurquer. C'est la bifurcation puis la sortie du processus d'origine qui pose problème.

(Il convient de noter que c'est autant un problème pour exécuter des programmes à partir de shells que pour exécuter des programmes à partir de gestionnaires de services, les utilisateurs voyant les programmes se terminer et provoquer une autre invite de shell presque immédiatement. En effet, juste aujourd'hui, quelqu'un demandait, encore une fois , à propos de l'exécution de programmes à partir du shell qui forkent et quittent le parent, à Pourquoi parfois, lorsque j'exécute un programme dans le terminal, il ne s'exécute pas dans le terminal?. )

Type=oneshotCe n'est probablement pas ce que vous voulez dans ce cas particulier, car le service n'est considéré comme prêt que lorsque l'ensemble du programme de service est terminé. Il a ses utilisations, mais par ses sons, ils ne s'appliquent pas à vous.

N'utilisez jamais Type=forking. Ce devrait être le dernier recours du désespoir, car presque aucun programme ne parle réellement du protocole . Ils font autre chose , qui n'est en fait pas ce protocole, qui n'est pas correctement interopérable avec ce protocole, et qui ne signale pas en fait l'état de préparation.

Lectures complémentaires

  • Jonathan de Boyne Pollard (2001). Erreurs à éviter lors de la conception de programmes Unix dæmon . Réponses fréquemment données.
  • Jonathan de Boyne Pollard (2015). Vous n'avez vraiment pas besoin de démoniser. Vraiment. . La maison systemd de l'horreur.
  • Jonathan de Boyne Pollard (2015). Problèmes de protocole de préparation avec Unix dæmons . Réponses fréquemment données.
  • https://unix.stackexchange.com/a/401611/5132