Comment démarrer automatiquement un service lors de l'exécution d'un conteneur Docker?

157

J'ai un Dockerfile pour installer le serveur MySQL dans un conteneur, que je commence ensuite comme ceci:

sudo docker run -t -i 09d18b9a12be /bin/bash

Mais le service MySQL ne démarre pas automatiquement, je dois exécuter manuellement (depuis le conteneur):

service mysql start

Comment démarrer automatiquement le service MySQL lorsque j'exécute le conteneur Docker?

mtmacdonald
la source
1
non, pour un service simple, le superviseur n'est pas nécessaire, cela rend compliqué pour l'utilisateur débutant
Larry Cai
8
vous voudrez peut-être copier le fichier docker ici au lieu de créer un lien vers un fichier qui n'existe plus
neo112
L'article de docker sur supervisord est maintenant ici: docs.docker.com/config/containers/multi-service_container J'ai utilisé la commande && tail pour faire fonctionner mon service - mais j'avais besoin d'ajouter "--cap-add SYS_PTRACE" au docker exécuter la commande.
Ted Cahall

Réponses:

205

Premièrement, il y a un problème dans votre Dockerfile:

RUN service mysql restart && /tmp/setup.sh

Les images Docker n'enregistrent pas les processus en cours d'exécution. Par conséquent, votre RUNcommande s'exécute uniquement pendant la docker buildphase et s'arrête une fois la génération terminée. Au lieu de cela, vous devez spécifier la commande lorsque le conteneur est démarré à l'aide des commandes CMDou ENTRYPOINTcomme ci-dessous:

CMD mysql start

Deuxièmement, le conteneur docker a besoin d'un processus (dernière commande) pour continuer à fonctionner, sinon le conteneur quittera / s'arrêtera. Par conséquent, la service mysql startcommande normale ne peut pas être utilisée directement dans le Dockerfile.

Solution

Il existe trois façons typiques de maintenir le processus en cours d'exécution:

  • Utilisation de la servicecommande et ajout de la commande non finale après cela, commetail -F

    CMD service mysql start && tail -F /var/log/mysql/error.log
    

Ceci est souvent préférable lorsque vous avez un seul service en cours d'exécution, car cela rend le journal produit accessible à docker.

  • Ou utilisez la commande de premier plan pour ce faire

    CMD /usr/bin/mysqld_safe
    

Cela ne fonctionne que s'il existe un script comme mysqld_safe.

  • Ou encapsulez vos scripts start.shet mettez-y fin

    CMD /start.sh
    

C'est mieux si la commande doit effectuer une série d'étapes, encore une fois, /start.shdoit rester en cours d'exécution.

Remarque

Pour les débutants, l'utilisation supervisordn'est pas recommandée. Honnêtement, c'est exagéré. Il est préférable d'utiliser un service / une commande unique pour le conteneur.

BTW: veuillez consulter https://registry.hub.docker.com pour les images de docker mysql existantes pour référence

Larry Cai
la source
Comment redémarreriez-vous le service une fois démarré dans le conteneur docker?
K - La toxicité du SO augmente.
3
@KarlMorrisondocker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
kaiser
1
Je ne recommanderais pas de suivre le journal des erreurs de MySQL pour déterminer si la base de données est en cours d'exécution ou non. Dans la plupart des configurations mysqld, le serveur récupérera des erreurs soe et ce faisant, le journal des erreurs sera fermé puis rouvert. Je ne suis pas non plus sûr que votre queue -F fonctionnera pour vous dans tous ou même certains cas.
Brian Aker
Je ne sais pas pourquoi, mais la première option de solution fonctionne bien pour le script de service. Lorsque vous n'utilisez pas tail, il échouera, même si le service est démarré (au moins pour le service tomcat7). Avec la queue ça marche. Dans les deux cas, vous devez utiliser le commutateur cap_add (- cap-add SYS_PTRACE pour l'exécution) avec au moins SYS_PTRACE
zhrist
1
non, voir plus dans stackoverflow.com/questions/46800594/…
Larry Cai
73

Dans votre Dockerfile, ajoutez à la dernière ligne

ENTRYPOINT service ssh restart && bash

Ça marche pour moi

Et voici le résultat:

root@ubuntu:/home/vagrant/docker/add# docker run -i -t ubuntu
 * Restarting OpenBSD Secure Shell server sshd   [ OK ]                                                                      
root@dccc354e422e:~# service ssh status
 * sshd is running
Jia
la source
2
c'est bien mais je pense que vous ne pouvez pas avoir un conteneur détaché de cette façon.
mdob du
1
Cela a très bien fonctionné pour moi. J'avais du mal à faire démarrer Nginx 1.8 automatiquement. L'ajout des éléments suivants peut vous être utile: RUN echo "daemon off;" >> /etc/nginx/nginx.conf RUN ln -sf / dev / stdout /var/log/nginx/access.log RUN ln -sf / dev / stderr /var/log/nginx/error.log
Lionel Morrison
1
Y a-t-il des inconvénients à cette solution?
srph
2
Démarrer enfin Bash est une mauvaise idée lorsque vous souhaitez arrêter vos services gracieusement, car de cette manière, le docker contaienr ne peut pas être arrêté docker stopou docker restartgracieusement, il peut simplement être tué.
Mohammed Noureldin
Je travaillais sur packer pour créer des images docker et cela semble résoudre mon problème avec le conaitner dans le fichier packer. "changes": ["ENTRYPOINT service nginx start && / bin / bash"]
karthik101
8

Facile! Ajoutez à la fin de dockerfile:

ENTRYPOINT service mysql start && /bin/bash
Thiago
la source
C'est la meilleure réponse qui résout mon problème actuel de conteneur Docker:, Docker version 18.09.7, build 2d0083dsans && /bin/bashle service s'arrêtera immédiatement
Long
7

Il y a une autre façon de le faire que j'ai toujours trouvée plus lisible.

Dites que vous voulez démarrer rabbitmq et mongodb lorsque vous l'exécutez, cela CMDressemblerait à ceci:

CMD /etc/init.d/rabbitmq-server start && \
    /etc/init.d/mongod start

Puisque vous ne pouvez en avoir qu'une CMDpar Dockerfileastuce, vous devez concaténer toutes les instructions avec &&, puis les utiliser \pour chaque commande pour démarrer une nouvelle ligne.

Si vous finissez par ajouter à beaucoup de ceux-ci, je vous suggère de mettre toutes vos commandes dans un fichier de script et de le démarrer comme @ larry-cai a suggéré:

CMD /start.sh
Francesco Casula
la source
3

Dans mon cas, j'ai une application Web PHP servie par Apache2 dans le conteneur docker qui se connecte à une base de données backend MYSQL. La solution de Larry Cai a fonctionné avec des modifications mineures. J'ai créé un entrypoint.shfichier dans lequel je gère mes services. Je pense que créer un entrypoint.shlorsque vous avez plus d'une commande à exécuter lorsque votre conteneur démarre est un moyen plus propre d'amorcer le docker.

#!/bin/sh

set -e

echo "Starting the mysql daemon"
service mysql start

echo "navigating to volume /var/www"
cd /var/www
echo "Creating soft link"
ln -s /opt/mysite mysite

a2enmod headers
service apache2 restart

a2ensite mysite.conf
a2dissite 000-default.conf
service apache2 reload

if [ -z "$1" ]
then
    exec "/usr/sbin/apache2 -D -foreground"
else
    exec "$1"
fi
M. Doomsbuster
la source
Mettez-le simplement à côté de votre Dockerfile. Ensuite, dans votre Dockerfile, vous devriez avoir une instruction qui copie ce fichier à l'emplacement souhaité. Ensuite, vous pointez l' ENTRYPOINT ['your location']instruction vers le fichier de script. N'oubliez pas de définir les autorisations d'exécution sur votre script. COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]. Dans cet exemple, j'ai copié mon point d'entrée dans le répertoire racine du conteneur docker.
M. Doomsbuster
où est Dockerfile?
Viktor Joras
3

J'ai le même problème lorsque je veux démarrer automatiquement le service ssh. J'ai trouvé cet ajout

/etc/init.d/ssh start
à
~ / .bashrc
peut le résoudre, mais vous seul l'ouvrez avec bash fera l'affaire.

Weiping.Chen
la source
1

J'ajoute le code suivant à /root/.bashrc pour exécuter le code une seule fois,

Veuillez valider le conteneur dans l'image avant d'exécuter ce script, sinon le fichier 'docker_services' sera créé dans les images et aucun service ne sera exécuté.

if [ ! -e /var/run/docker_services ]; then
    echo "Starting services"
    service mysql start
    service ssh start
    service nginx start
    touch /var/run/docker_services
fi
user136685
la source
1

Voici comment démarrer automatiquement le service MySQL chaque fois que le conteneur docker s'exécute.

Dans mon cas, je dois exécuter non seulement MySQL mais aussi PHP, Nginx et Memcached

J'ai les lignes suivantes dans Dockerfile

RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
EXPOSE 3306
CMD service mysql start && service php-fpm start && nginx -g 'daemon off;' && service memcached start && bash

L'ajout de && bash permettrait à Nginx, MySQL, PHP et Memcached de fonctionner dans le conteneur.

Chris
la source
1

Cela ne fonctionne pas CMD service mysql start && /bin/bash

Cela ne fonctionne pas CMD service mysql start ; /bin/bash ;

- Je suppose que le mode interactif ne prendrait pas en charge le premier plan.

Cela marche !! CMD service nginx start ; while true ; do sleep 100; done;

Cela marche !! CMD service nginx start && tail -F /var/log/nginx/access.log

attention, vous devez utiliser docker run -p 80:80 nginx_bashsans paramètre de commande.

utilisateur3073309
la source
0

La documentation suivante du site Web Docker montre comment implémenter un service SSH dans un conteneur Docker. Il doit être facilement adaptable à votre service:

Une variante de cette question a également été posée ici:

Zammalad
la source
L'outil nsenter est une autre approche pour entrer dans un conteneur, sans nécessiter l'installation d'un serveur SSH: github.com/jpetazzo/nsenter . Mais cette approche nécessite un accès à votre hôte Docker (généralement un accès SSH suffit).
Fabien Balageas
Le lien docs.docker.com/sorry/#/examples/running_ssh_service ne fonctionne pas. Pouvez-vous le mettre à jour?
Ankur
0
docker export -o <nameOfContainer>.tar <nameOfContainer>

Il se peut que vous deviez élaguer le conteneur existant à l'aide de Docker Prune ...

Importer avec les modifications requises:

cat <nameOfContainer>.tar | docker import -c "ENTRYPOINT service mysql start && /bin/bash" - <nameOfContainer>

Exécutez le conteneur par exemple avec l'option toujours redémarrer pour vous assurer qu'il reprendra automatiquement après le recyclage de l'hôte / démon:

docker run -d -t -i --restart always --name <nameOfContainer> <nameOfContainer> /bin/bash

Note latérale: À mon avis, il est raisonnable de démarrer uniquement le service cron en laissant le conteneur aussi propre que possible, puis de modifier simplement crontab ou cron.hourly, .daily etc ... avec les scripts de contrôle / surveillance correspondants. La raison en est que vous ne comptez que sur un démon et en cas de changements, il est plus facile avec ansible ou puppet de redistribuer les scripts cron au lieu de suivre les services qui commencent au démarrage.

Daniel
la source