web-dev-qa-db-fra.com

Le serveur Rails est toujours en cours d'exécution dans un nouveau conteneur de menu fixe ouvert.

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 | => RunRails 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

31
handkock

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.

44
TopperH

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 ""

35
Brendon Whateley

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!

5
charlesdg

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

2
mrpepo877

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)

  1. 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é. 

  2. 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

2
Dan Key

Ceci est une version adaptée de Brendon Whateleys ???? répondre pour

Solution Docker Compose

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

????

1
davegson

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.

0
Jimmy M.G. Lim

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.

0
Sheetal Kaul