web-dev-qa-db-fra.com

Comment garder le conteneur Docker actif après le démarrage des services?

J'ai vu une série de tutoriels qui semblent faire la même chose que j'essaie de faire, mais pour une raison quelconque, mes conteneurs Docker sont fermés. En gros, je configure un serveur Web et quelques démons dans un conteneur Docker. Je fais les dernières parties de ceci à travers un script bash appelé run-all.sh que je lance via CMD dans mon fichier Docker. run-all.sh ressemble à ceci:

service supervisor start
service nginx start

Et je le lance dans mon Dockerfile comme suit:

CMD ["sh", "/root/credentialize_and_run.sh"]

Je peux voir que tous les services démarrent correctement lorsque j'exécute manuellement des tâches (par exemple, passer à l'image avec -i -t/bin/bash), et tout se présente comme si elle fonctionnait correctement lorsque j'exécute l'image, mais elle se ferme une fois cela termine le démarrage de mes processus. J'aimerais que les processus fonctionnent indéfiniment et, autant que je sache, le conteneur doit continuer à fonctionner pour que cela se produise. Néanmoins, quand je lance docker ps -a, je vois:

➜  docker_test  docker ps -a
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS                      PORTS               NAMES
c7706edc4189        some_name/some_repo:blah   "sh /root/run-all.sh   8 minutes ago       Exited (0) 8 minutes ago                        Grave_jones

Ce qui donne? Pourquoi est-ce sortir? Je sais que je pourrais simplement mettre une boucle while à la fin de mon script bash pour continuer, mais quel est le bon moyen de l'empêcher de se terminer?

124
Eli

Ce n'est pas vraiment comment vous devriez concevoir vos conteneurs Docker.

Lors de la conception d'un conteneur Docker, vous êtes censé le construire de sorte qu'un seul processus soit en cours d'exécution (c'est-à-dire que vous devez avoir un conteneur pour Nginx et un pour supervisord ou l'application en cours d'exécution); En outre, ce processus devrait s’exécuter au premier plan.

Le conteneur "se fermera" quand le processus se terminera (dans votre cas, ce processus est votre script bash).


Toutefois, si vous avez réellement besoin (ou souhaitez) d'exécuter plusieurs services dans votre conteneur Docker, envisagez de commencer à partir de "Docker Base Image " , qui utilise runit comme processus de pseudo-initiation (runit restera en ligne pendant l'exécution de Nginx et Supervisor), qui restera au premier plan pendant que vos autres processus feront leur travail .

Ils ont une documentation substantielle, vous devriez donc être capable de réaliser ce que vous essayez de faire assez facilement.

43
Thomas Orozco

Si vous utilisez un fichier Dockerfile, essayez:

ENTRYPOINT ["tail", "-f", "/dev/null"]

(Évidemment, c'est uniquement à des fins de développement, vous ne devriez pas avoir besoin de garder un conteneur en vie à moins qu'il ne soit en train d'exécuter un processus, par exemple nginx ...)

105
Soft Bullets

Je viens d'avoir le même problème et j'ai découvert que si vous exécutez votre conteneur avec le drapeau -t et -d, il continue à fonctionner.

docker run -td <image>

Voici ce que font les drapeaux (selon docker run --help):

-d, --detach=false         Run container in background and print container ID
-t, --tty=false            Allocate a pseudo-TTY

Le plus important est le drapeau -t. -d vous permet simplement d'exécuter le conteneur en arrière-plan.

71
arne.z

Il s’exécute parce que le script Shell s’exécute d’abord en tant que PID 1. Lorsque cette opération est terminée, le PID 1 est supprimé et docker ne s’exécute que lorsque PID 1 l’est.

Vous pouvez utiliser supervisor pour tout faire. S'il est exécuté avec l'indicateur "-n", il ne doit pas être démonisé. Il restera donc comme premier processus:

CMD ["/usr/bin/supervisord", "-n"]

Et votre supervisord.conf:

[supervisord]
nodaemon=true

[program:startup]
priority=1
command=/root/credentialize_and_run.sh
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false
startsecs=0

[program:nginx]
priority=10
command=nginx -g "daemon off;"
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.log
autorestart=true

Ensuite, vous pouvez avoir autant de processus que vous le souhaitez et le superviseur se chargera de les redémarrer si nécessaire.

De cette façon, vous pouvez utiliser supervisord dans les cas où vous pourriez avoir besoin de nginx et de php5-fpm et où il n’a pas de sens de les séparer.

39
phazei

vous pouvez exécuter plain cat sans les arguments mentionnés par bro @ Sa'ad pour que le conteneur fonctionne simplement [ne fait rien d'autre que d'attendre l'entrée de l'utilisateur] (le plugin Docker de Jenkins fait la même chose)

35
Serge Velikanov

Assurez-vous que vous ajoutez daemon off; à votre fichier nginx.conf ou exécutez-le avec CMD ["nginx", "-g", "daemon off;"] conformément à l'image officielle de nginx.

Ensuite, utilisez ce qui suit pour exécuter à la fois supervisor en tant que service et nginx en tant que processus de premier plan empêchant le conteneur de quitter.

service supervisor start && nginx

Dans certains cas, vous aurez besoin de plusieurs processus dans votre conteneur. Par conséquent, le fait de forcer le conteneur à disposer exactement d'un processus ne fonctionnera pas et risque de créer davantage de problèmes de déploiement.

Vous devez donc comprendre les compromis et prendre votre décision en conséquence.

12
iTech

Capturez le PID du processus ngnix dans une variable (par exemple $ NGNIX_PID) et à la fin du fichier de point d’entrée, faites

wait $NGNIX_PID 

De cette façon, votre conteneur devrait fonctionner jusqu'à ce que ngnix soit actif. Lorsque ngnix s'arrête, le conteneur s'arrête également

5
user2825611

Motivation:

Il y a rien de mal à exécuter plusieurs processus à l'intérieur d'un conteneur de menu fixe . Si on aime utiliser Docker comme un poids léger VM - qu’il en soit ainsi. D'autres aiment scinder leurs applications en micro services. Moi pense: Une pile de lampe dans un conteneur? Tout simplement génial.

La réponse:

Stick avec une bonne image de base comme le image de base de phusion . Il y en a peut-être d'autres. Commentez s'il vous plaît.

Et ceci n'est encore qu'un plaidoyer supplémentaire pour le superviseur. Parce que l'image de base de phusion fournit au superviseur d'autres éléments tels que la configuration de cron et de paramètres régionaux. Ce que vous aimez avoir configuré lors de l’exécution d’une machine virtuelle aussi légère. Pour ce que cela vaut, fournit également des connexions SSH dans le conteneur.

L'image de phusion elle-même ne fera que commencer et continuer à fonctionner si vous émettez cette instruction de base du docker:

moin@stretchDEV:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
moin@stretchDEV:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS
521e8a12f6ff        phusion/baseimage   "/sbin/my_init"     12 seconds ago      Up 11 seconds

Ou simple:

Si une image de base ne vous convient pas ... Pour que le CMD rapide puisse continuer à fonctionner, je supposerais quelque chose comme ceci pour bash:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

Ou ceci pour busybox:

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"

C'est bien, car il va sortir immédiatement sur un docker stop. Simplement sleep ou cat prendra quelques secondes avant la fermeture du conteneur.

3
itsafire