Fabric: Les scripts d'initialisation ne parviennent souvent pas à démarrer leurs démons

Créé le 19 août 2011  ·  19Commentaires  ·  Source: fabric/fabric

La description

J'ai reçu plusieurs rapports à ce sujet sur IRC, ainsi qu'un commentaire sur le # 350, et maintenant un fil de discussion sur la liste de diffusion .

Aucune cause claire pour le moment, et bien que cela ait été signalé plusieurs fois, je ne pense pas que ce soit un problème constant ou que nous en entendrions beaucoup plus. Dans certains tests très limités de mon côté jusqu'à présent, je peux recréer le problème peut-être 30 à 50% du temps - mais il est reproductible.

Le symptôme est simplement que les scripts de style init chargés de démarrer les démons puis de les renvoyer immédiatement, renverront OK, le code de retour de 0 et le message d'état "success" seront imprimés sur stdout - mais ne feront pas tourner le démon en question.

Mon test personnel a été effectué via le dernier master ciblant une VM Ubuntu 10.04 (Lucid) et le script d'initialisation du package Apache2.


Présentée à l' origine par Jeff Forcier ( bitprophet ) sur 2011-07-23 à 19:25 EDT

Rapports

  • Lié à # 350: fabric raccroche une commande à distance (pour le programme démon)
Bug Docs Wart

Commentaire le plus utile

Juste face à ce problème.
J'ai eu une situation où je ne peux pas utiliser tty = False parce que j'exécute la commande avec sudo.
L'ajout de >& /dev/null < /dev/null & s'exécute bien mais le processus n'a pas été lancé.

J'ai résolu le problème de l'ajout d'un sommeil après la ligne d'exécution de la commande: nohup java -jar text.jar & sleep 5; exit 0

Tous les 19 commentaires

Jeff Forcier ( bitprophet ) a publié:


J'ai instrumenté le script init que je teste et tout semble fonctionner de la même manière (c'est-à-dire un vrai succès ou de faux scénarios de réussite), ce qui implique que le problème se situe dans l'appel apachectl le script lui-même fait.

Commencer à réfléchir à ce que pourrait être la cause de notre côté:

  • Comme il est semi-aléatoire, cela me fait penser aux problèmes passés avec le sous-système IO en proie à des conditions de course. Cependant, je ne peux pas vraiment penser à la façon dont cela pourrait éventuellement affecter quelque chose à l'extrémité distante de cette manière, et les conditions de course étaient toutes locales de toute façon.

    • Une façon de tester cela pourrait être de voir si ce problème survient avec Fab 0.9.x et pty = True (pour correspondre à la valeur par défaut actuelle dans 1.x).

  • Cela pourrait aussi être simplement lié à pty - je ne me souviens pas que c'était un problème avant la version 1.0 et que la définition de pty sur True était l'un des changements majeurs dans le comportement par défaut. Encore une fois, je ne vois pas pourquoi l'utilisation du sous-système request-a-pty de SSH entraînerait le comportement des scripts d'initialisation de cette façon.

    • Un test ici serait d'utiliser ssh -t <hostname> <command> et de voir si cela reproduit également le problème.


sur 2011-07-23 à 19:45 EDT

Jeff Forcier ( bitprophet ) a publié:


apache2ctl lui-même est aussi simplement un script Bash wrapper appelant /usr/sbin/apache2 , qui est un lien symbolique vers un exécutable binaire réel dans l'emplacement d'installation d'Apache mpm-worker. Plus précisément, dans l'utilisation normale de start , il appelle /usr/sbin/apache2 -k start . Comme précédemment, apache2ctl ne semble pas se comporter différemment dans les deux scénarios différents, re: return value ou quelles sections sont exécutées.

/usr/sbin/apache2 sont relativement limités (même sur le site d'Apache), indiquant uniquement que vous devriez utiliser apachectl pour configurer des variables d'environnement (ce qui est précis - l'exécution de apache2 par elle-même est assez évidemment avec des erreurs concernant ces variables n'étant pas définies.)

L'examen de la sortie de env juste avant l'invocation de apache2ctl de apache2 ne donne que quelques éléments: utilisateur, groupe, emplacement du fichier pid et langue. Celles-ci ne changent pas entre les situations de réussite et d'échec. J'espérais un peu qu'il y aurait quelque chose dans les divers paramètres de sourcings et d'env var dans les wrappers qui changerait parfois, mais non.


Jusqu'à présent, cela ne va nulle part utile. Il est temps de tester les idées ci-dessus (pty, ssh) pour voir ce qui change là-bas.


sur 2011-07-23 à 20:46 EDT

Jeff Forcier ( bitprophet ) a publié:


Avec pty=False , cela semble fonctionner beaucoup mieux (comme le laisse entendre le commentaire de Max au # 350). Avec le paramètre True par défaut, je voyais des échecs environ 5/10 fois, parfois quelques plus ou moins. Avec False, je viens de l'exécuter environ 15 fois de suite sans échec. Pas un statisticien mais cela me semble plutôt bien.

L'exécution manuelle de ssh donne des résultats similaires: ssh -t <host> sudo /etc/init.d/apache2 start échouera silencieusement à démarrer Apache environ 50% du temps. La même chose avec -T (force no pty) et ça démarre 100% du temps.

Ce n'est donc pas la faute de Fabric; c'est quelque chose de plus profond où ces scripts d'initialisation se comportent mal quand un pseudo-tty de style SSH est en jeu.


Je vais creuser un peu plus pour la curiosité, mais il semble que la "solution" voici une nouvelle FAQ indiquant d'utiliser pty=False lorsque ce problème est rencontré.


le 23/07/2011 à 20h59 HAE

Jeff Forcier ( bitprophet ) a publié:


Oui, ne trouvant rien qui explique ce comportement, malheureusement. Compte tenu des résultats ci-dessus, je pense qu'une FAQ est certainement la voie à suivre.


le 23/07/2011 à 22h35 HAE

Hugo Garza (hiro2k) a posté:


Ughh je viens de rencontrer ça hier, j'aurais aimé voir ce bug, heureusement j'ai essayé de régler pty = False et cela a fonctionné aussi. Merci pour l'explication, au moins ce n'est pas une faute de tissus. Maintenant, vous me demandez vraiment pourquoi cela échoue.


le 02/08/2011 à 13h27 HAE

Êtes-vous sûr que ce n'est pas seulement un problème de script bash? Je veux dire avec mon fil de liste de diffusion. C'étaient juste des scripts bash qui ont lancé java et weblogic.

FWIW, j'obtiens ce comportement horrible sur à peu près toutes les machines Ubuntu que je fais tourner sur EC2.

Il est également reproductible avec les tâches lancées via un écran détaché screen -d -m someBackgroundTask .

Je dois mentionner que généralement pty=False résout le problème, mais j'ai vu des cas où ce n'était pas le cas.

@yuvadm - dans les cas où pty = False ne résout pas le problème, le problème peut-il encore être recréé en utilisant une commande ssh régulière (comme mentionné ci-dessus)? Pour autant que j'ai vu, c'est un problème SSH et non un problème Fabric, mais il serait bon de savoir s'il y a des situations où cela ne correspond pas.

C'est un angle intéressant à vérifier, je vous reviendrai sur celui-là ...

J'ai reproduit ce problème. Le client est Ubuntu 10.04.3 LTS, le serveur est "Ubuntu 8.04.4 LTS (serveur)".
Le client SSH est "OpenSSH_5.3p1 Debian-3ubuntu7, OpenSSL 0.9.8k 25 mars 2009", le serveur ssh est "OpenSSH_4.7p1 Debian-8ubuntu1, OpenSSL 0.9.8g 19 octobre 2007". Le tissu est "1.3.3 final".

Le problème est là à 100% avec pty = True, et il disparaît avec pty = False.

En vous connectant à d'autres serveurs, le problème n'est pas toujours présent lorsque pty = True.

Dans mon cas, pour les tests, j'exécute une commande très simple: "nohup sleep 100> / tmp / xxx 2> & 1

J'ai été mordu par ça, seulement sur EC2 comme il semble (je ne l'ai pas vu sur mon Linode, mais je ne suis pas sûr à 100%). La définition de pty = False semble résoudre ce problème.

Juste face à ce problème.
J'ai eu une situation où je ne peux pas utiliser tty = False parce que j'exécute la commande avec sudo.
L'ajout de >& /dev/null < /dev/null & s'exécute bien mais le processus n'a pas été lancé.

J'ai résolu le problème de l'ajout d'un sommeil après la ligne d'exécution de la commande: nohup java -jar text.jar & sleep 5; exit 0

Merci spodgruskiy,

Vos conseils fonctionnent pour moi.
J'avais essayé d'écrire fab tp démarrer un cluster strom avec les commandes suivantes.

  1. run ('nohup ./bin/storm nimbus> & / dev / null </ dev / null &', pty = False)
  2. run ('nohup ./bin/storm nimbus> & / dev / null </ dev / null &')
  3. run ("screen -d -m './bin/storm nimbus'", pty = False)
  4. run ("|| écran -d -m './bin/storm nimbus'")

Mais aucun d'entre eux ne fonctionne, les nimbus n'ont pas du tout commencé. Je ne comprends pas ce qui s'est passé.
Bref, merci.

+1 pour l'astuce du sommeil

nécessaire pour travailler sur des systèmes avec des exigences

sudo ('start service; sleep .5') et tout va bien!

Lorsque vous utilisez 'sudo ()' et que RequireTty est activé sur le système distant pour l'accès sudo, vous pouvez utiliser 'set -m; un servicestart 'pour empêcher l'envoi du SIGHUP au processus démarré par le script init.

Voir http://stackoverflow.com/a/14866774 pour une explication plus détaillée sur bash interactif par rapport à non interactif et comment cela affecte le contrôle des tâches.

Je suis curieux, quel est le problème ssh ici?

pty = faux fonctionne pour moi

Ce n'est pas vraiment un problème SSH, c'est plutôt le comportement subtil autour des modes non interactifs / interactifs BASH et de la propagation du signal vers les groupes de processus.

Ce qui suit est basé sur http://stackoverflow.com/questions/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 et http: //www.itp.uzh.ch/~dpotter/howto/daemonize , avec certaines hypothèses non entièrement validées, mais les tests sur la façon dont cela fonctionne semblent confirmer.

pty / tty = faux

Le shell bash lancé se connecte au stdout / stderr / stdin du processus démarré et continue à s'exécuter jusqu'à ce qu'il n'y ait rien attaché aux sockets et que ses enfants soient sortis. Un bon processus de démon s'assurera qu'il n'attend pas que ses enfants quittent, fourchent un processus enfant puis sortent. Dans ce mode, aucun SIGHUP ne sera envoyé au processus fils par SSH. Je pense que cela fonctionnera correctement pour la plupart des scripts exécutant un processus qui gère la désamonisation et n'a pas besoin d'être mis en arrière-plan. Là où les scripts d'initialisation utilisent '&' pour l'arrière-plan d'un processus, il est probable que le problème principal sera de savoir si le processus en arrière-plan tente jamais de lire à partir de stdin car cela déclenchera un SIGHUP si la session est terminée.

pty / tty = vrai *

Si le script d'initialisation arrière-plan du processus a commencé, le shell BASH parent retournera un code de sortie à la connexion SSH, qui à son tour cherchera à quitter immédiatement car il n'attend pas qu'un processus enfant se termine et n'est pas bloqué sur stdout / stderr / stdin. Cela entraînera l'envoi d'un SIGHUP au groupe de processus du shell bash parent, qui, puisque le contrôle des travaux est désactivé en mode non interactif dans bash, inclura les processus enfants qui viennent d'être lancés. Lorsqu'un processus démon démarre explicitement une nouvelle session de processus lors du forking ou dans le processus forké, il ou ses enfants ne recevront pas le SIGHUP du processus parent BASH sortant. Notez que ceci est différent des travaux suspendus qui verront un SIGTERM.

Je soupçonne que les problèmes autour de cela ne fonctionnent que parfois avec une légère condition de course. Si vous regardez l'approche standard de la désamonisation - http://www.itp.uzh.ch/~dpotter/howto/daemonize , vous verrez que dans le code la nouvelle session est créée par le processus forké qui peut ne pas être s'exécuter avant la sortie du parent, ce qui entraîne le comportement aléatoire de réussite / échec mentionné ci-dessus. Une instruction sleep laissera suffisamment de temps au processus forké pour créer une nouvelle session, c'est pourquoi cela fonctionne dans certains cas.

pty / tty = true et le contrôle des tâches est explicitement activé dans bash

SSH ne se connectera pas au stdout / stderr / stdin du shell bash ou à tout processus enfant lancé, ce qui signifiera qu'il se fermera dès que le shell bash parent a commencé à avoir terminé d'exécuter les commandes demandées. Dans ce cas, avec le contrôle des tâches explicitement activé, tous les processus lancés par le shell bash avec `` & '' en arrière-plan seront placés dans une session distincte immédiatement et ne recevront pas le signal SIGHUP lorsque le processus parent de la session BASH se terminera ( Connexion SSH dans ce cas).

Ce qu'il faut réparer

Je pense que les solutions doivent simplement être explicitement mentionnées dans la documentation des opérations run / sudo en tant que cas particulier lorsque vous travaillez avec des processus / services en arrière-plan. En gros, utilisez «pty = false», ou lorsque ce n'est pas possible, activez explicitement le contrôle des travaux comme première commande, et le comportement sera correct.

Comme je l'ai mentionné ici fabrickit (un emballage de bibliothèques de tissus) https://github.com/HyukjinKwon/fabrickit/commit/cceb8bfb8f960a3ac41b24c64b8358bd6e7a0366

Vous pouvez tout à fait facilement démarrer un programme en tant que démon sans configuration ni paramètres spécifiques.
C'est de toute façon une sorte d'exécution de Shell et il devrait donc y avoir un moyen de faire ce que Shell peut faire.

Essaye ça:

run("sh -c '((nohup %s > /dev/null 2> /dev/null) & )'" % cmd, pty=False)

J'ai essayé cela et cela fonctionne parfaitement bien même s'il n'implémente pas de programmation supplémentaire pour s'exécuter en tant que démon (même juste un programme écrivant «Hello» dans une boucle while fonctionne très bien).

Cette page vous a été utile?
0 / 5 - 0 notes