Je souhaite déployer mon projet Rails avec Docker. J'utilise donc Docker-Compose. Mais je reçois un message d'erreur étrange. Quand je lance docker-compose-up (cela contient db-container avec postgresql, redis et web avec Rails), je reçois un
web_1 | => Booting Puma
web_1 | => Rails 4.2.4 application starting in production on http://0.0.0.0:3000
web_1 | => Run
Rails server -hfor more startup options
web_1 | => Ctrl-C to shutdown server
web_1 | A server is already running. Check /usr/src/app/tmp/pids/server.pid.
web_1 | Exiting
Alors je ne comprends pas pourquoi je reçois ce message, car à chaque fois que je lance la composition fixe, de nouveaux conteneurs démarrent, pas le précédent. Même si je souhaite supprimer ces server.pid
, je ne suis pas en mesure de le faire, car ce conteneur n'est pas en cours d'exécution.
mon fichier docker-compose.yml
web:
dockerfile: Dockerfile-Rails
build: .
command: bundle exec Rails s -p 3000 -b '0.0.0.0'
ports:
- "80:3000"
links:
- redis
- db
environment:
- REDISTOGO_URL=redis://user@redis:6379/
redis:
image: redis
db:
dockerfile: Dockerfile-db
build: .
env_file: .env_db
Dockerfile-Rails
FROM Rails:onbuild
ENV Rails_ENV=production
Je ne pense pas avoir besoin de poster tous mes Dockerfiles
UPD: Je l'ai corrigé par moi-même: je viens de supprimer tous mes conteneurs et de relancer le docker-compose up
Vous utilisez une image onbuild, votre répertoire de travail est donc monté dans l'image du conteneur. Cela est très utile pour le développement, car votre application est mise à jour en temps réel lorsque vous modifiez votre code et votre système hôte est mis à jour, par exemple lorsque vous exécutez une migration.
Cela signifie également que votre répertoire tmp du système hôte sera écrit avec le fichier pid chaque fois qu'un serveur est en cours d'exécution et y restera si le serveur n'est pas arrêté correctement.
Il suffit d’exécuter cette commande à partir de votre système hôte:
Sudo rm tmp/pids/server.pid
Cela peut être très pénible lorsque vous utilisez, par exemple, Foreman sous Docker-Composer, car appuyer simplement sur Ctrl + C ne supprimera pas le fichier PID.
Le même problème me stoppa un peu jusqu'à ce que je sache ce qui se passait réellement. La vraie réponse est plus bas ... Au début, vous voudrez peut-être essayer quelque chose comme la commande suivante dans votre fichier docker-compose.yml:
command: /bin/sh -c "rm -f /Rails/tmp/pids/server.pid && Rails server puma"
(J'utilise Alpine et busybox pour garder les choses minuscules, donc pas de bash! Mais le -c fonctionnera aussi avec bash) Cela supprimera le fichier s'il existe afin que vous ne soyez pas bloqué par le problème que le conteneur garde sortant et assis là incapable d’exécuter des commandes.
Malheureusement, ce n'est PAS une bonne solution car vous ajoutez une couche supplémentaire de/bin/sh devant le serveur, ce qui empêche le serveur de recevoir la commande d'arrêt. Le résultat est que les commandes d'arrêt du menu fixe ne donneront pas une sortie en douceur et le problème se produira toujours.
Vous pouvez simplement exécuter la commande rm en utilisant docker-compos up pour supprimer le fichier, puis redéfinir la commande sur le serveur et poursuivre.
Cependant, la vraie solution consiste à créer un fichier simple docker-entry.sh et à vous assurer de l'appeler à l'aide du formulaire exec Documentation Entrypoint afin que les signaux (comme l'arrêt) parviennent au processus du serveur.
#!/bin/sh
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
exec bundle exec "$@"
NOTE: nous utilisons exec sur la dernière ligne pour nous assurer que Rails sera exécuté en tant que pid 1 (c'est-à-dire sans shell supplémentaire) et ainsi obtenir les signaux à arrêter. Et puis dans le fichier Dockerfile (ou le fichier compose.yml), ajoutez le point d’entrée et la commande
# Get stuff running
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["Rails", "server", "puma"]
Et encore une fois, vous DEVEZ utiliser le format [] pour qu’il soit exécuté au lieu de s’exécuter en tant que sh -c ""
Ce que j’ai fait, c’est d’aller sur le bash Shell de docker:
docker-compose run web /bin/bash
puis supprimez le fichier suivant
rm tmp/pids/server.pid
J'espère que ça aide!
pour mon travail:
docker-compose run web bash
puis allez dossier par dossier avec la commande cd (j'utilise win 7 toolbox).
rm tmp/pids/server.pid
Pour ceux qui ont un problème quand il n'y a pas de tmp/pids/server.pid
, existe réellement:
(Docker version 1.11.2, build b9f10c9)
La solution qui a fonctionné pour moi consiste à ajouter une commande exacte à docker-compose.yml
, par exemple:
command:
Rails s -b0
Avoir cette commande, qui peut en fait simplement dupliquer le CMD de Dockerfile - le problème avec .pid
n'est pas affiché.
Une autre option, lorsque vous devez utiliser le CMD de Dockerfile, consiste à exécuter l’option --build
pour reconstruire l’image:
docker-compose up --build
Bien que cela prenne du temps, la première solution est plus pratique
Ceci est une version adaptée de Brendon Whateleys ???? répondre pour
1. Créer docker-entrypoint.sh
#!/bin/bash
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
exec bundle exec "$@"
2. Adaptez votre docker-compose.yml
services:
web:
build: .
entrypoint: /myapp/docker-entrypoint.sh
command: ["Rails", "server", "-b", "0.0.0.0"]
volumes:
- .:/myapp
ports:
- "3000:3000"
Notez que vous devrez indiquer le chemin d'accès à l'endroit où vous avez monté votre application, à savoir: /myapp
2.5 Si vous rencontrez une erreur d'autorisation
Exécutez ceci dans votre terminal avant avec docker-compose up
ou en construisant votre image. Merci sajadghawami .
chmod +x docker-entrypoint.sh
3. Profitez de ne plus avoir à supprimer server.pid manuellement
????
Dans votre fichier docker-compose.yml, sous le conteneur d'application lui-même, vous pouvez utiliser:
commande: ["rm /your-app-path/tmp/pids/server.pid && bundle exec bin/Rails s -p 3000 -b '0.0.0.0'"]
ou
commande: ["rm /your-app-path/tmp/pids/server.pid; foreman start"]
la raison pour soit ";" ou "&&" signifie que ce dernier enverra un signal de sortie si rm ne parvient pas à trouver le fichier, forçant votre conteneur à s'arrêter prématurément. le prieur continuera à exécuter.
pourquoi est-ce causé en premier lieu? le rationnel est que si le serveur (puma/thin/quoique que ce soit) ne se ferme pas correctement, il laissera un pid sur la machine hôte provoquant une erreur de sortie.
Si vous vous sentez aventureux, n'hésitez pas à rechercher server.pid dans la base de code et à vérifier où le pid est écrit. De cette façon, vous pouvez vérifier si le fait de ne pas l'autoriser à écrire corrige le problème racine pour vous. Parce que, apparemment, la création de pid vous empêche d’exécuter des services en double dans deux conteneurs différents. Mais cela devrait être pris en charge dans docker tel quel. Si, pour une raison quelconque, ce n’est pas le cas, la méthode de la collision portuaire devrait en tenir compte et vous alerter. Note: Je n'ai pas encore essayé cette approche car cela déplace le système en général :)
Alternativement, vous pouvez avoir des commandes dans votre Makefile. Où la tâche fait ceci:
tâche:
docker-compose stop nom_service
docker-compose rm nom_service
rm -f ./tmp/pids/server.pid (ou chemin relatif de votre fichier pid)
docker-compos up up nom_service
Puis vrooom make task
dans le terminal et appuyez sur Entrée . Les commandes de tâches ci-dessus supposent que le service que vous souhaitez exécuter se trouve dans un fichier nommé docker-compose.yml.
Si le nom est différent, alors la commande
docker-compose stop nom_service -> docker-compose -f votre-composition-nom_fichier.yml stop service_name
etc., etc.
==================== Est revenu pour mettre à jour ceci. J'ai donc essayé de commenter les fonctionnalités de ma méthode write_pid. En gros, conservez la définition de la méthode, mais ne la faites rien faire. Cela fonctionne bien jusqu'à présent. Il n'écrit pas du tout le pid. Si vous utilisez vos services dans Docker, je pense que cela est totalement sûr.