Comment démarrer un conteneur Docker arrêté avec une commande différente?

251

Je voudrais démarrer un conteneur Docker arrêté avec une commande différente, car la commande par défaut se bloque - ce qui signifie que je ne peux pas démarrer le conteneur, puis utiliser 'docker exec'.

Fondamentalement, je voudrais démarrer un shell afin de pouvoir inspecter le contenu du conteneur.

Heureusement, j'ai créé le conteneur avec l'option -it!

aaa90210
la source

Réponses:

380

Trouvez votre identifiant de conteneur arrêté

docker ps -a

Validez le conteneur arrêté:

Cette commande enregistre l'état du conteneur modifié dans une nouvelle image user/test_image

docker commit $CONTAINER_ID user/test_image

Démarrer / exécuter avec un point d'entrée différent:

docker run -ti --entrypoint=sh user/test_image

Description de l'argument point d'entrée: https://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime

Remarque:

Les étapes ci-dessus démarrent simplement un conteneur arrêté avec le même état de système de fichiers. C'est formidable pour une enquête rapide. Mais les variables d'environnement, la configuration du réseau, les volumes attachés et les autres membres du personnel ne sont pas hérités, vous devez spécifier explicitement tous ces arguments.

Les étapes pour démarrer un conteneur arrêté ont été empruntées à partir d'ici: (dernier commentaire) https://github.com/docker/docker/issues/18078

Dmitriusan
la source
1
non, les images sont en lecture seule. Il enregistre l'état du conteneur modifié dans une nouvelle image test_image
Dmitriusan
4
cela manque presque toute la config sur env, volumes, UID,… Tout ce qu'il a en commun avec le conteneur arrêté est le système de fichiers (ce qui est peut-être suffisant pour certains)
Florian Klein
4
Ce serait formidable si je pouvais en quelque sorte obtenir le même environnement, la configuration réseau, les volumes attachés. Est-il possible de convertir la inspectsortie en une configuration utilisée lors de l'exécution suivante?
Otheus
2
@Webman, oui, mais ce n'est pas le cas pour les volumes qui ont été montés avant l'arrêt d'un conteneur. Vous devrez attacher explicitement les mêmes volumes lors du prochain démarrage du conteneur
Dmitriusan
1
@ EmreTapcı, je pense que faire cela est contraire à l'idéologie Docker. Les conteneurs sont destinés à être une entité run-and-jetable à usage unique, contrairement aux machines virtuelles. Vous pouvez essayer de suivre la réponse aaa90210 , mais ce serait un hack.
Dmitriusan
126

Modifiez ce fichier (correspondant à votre conteneur arrêté):

vi /var/lib/docker/containers/923...4f6/config.json

Modifiez le paramètre "Path" pour pointer vers votre nouvelle commande, par exemple / bin / bash. Vous pouvez également définir le paramètre "Args" pour passer des arguments à la commande.

Redémarrez le service docker (notez que cela arrêtera tous les conteneurs en cours d'exécution):

service docker restart

Listez vos conteneurs et assurez-vous que la commande a changé:

docker ps -a

Démarrez le conteneur et attachez-le, vous devriez maintenant être dans votre coquille!

docker start -ai mad_brattain

A travaillé sur Fedora 22 à l'aide de Docker 1.7.1.

REMARQUE: si votre shell n'est pas interactif (par exemple, vous n'avez pas créé le conteneur d'origine avec l'option -it), vous pouvez remplacer la commande par "/ bin / sleep 600" ou "/ bin / tail -f / dev / null" pour vous donner suffisamment de temps pour faire "docker exec -it CONTID / bin / bash" comme une autre façon d'obtenir un shell.

REMARQUE 2: les nouvelles versions de docker ont config.v2.json, où vous devrez modifier Entrypoint ou Cmd (merci user60561).

aaa90210
la source
44
mes yeux. mes yeux. J'espère que c'est une demande de fonctionnalité quelque part pour gérer cela correctement dans Docker.
gertvdijk
2
@AlexeyStrakh, vous pouvez essayer d'exécuter "/ usr / bin / sleep 600" puis faire "docker exec -it / bin / bash" pour obtenir un shell. Bien que je ne sais pas comment mettre des paramètres sur cette variable Path. Sinon, essayez de trouver une autre commande qui restera en vie assez longtemps pour que vous puissiez faire un exec, ou voyez la réponse de Dmitriusan.
aaa90210
3
c'est la seule réponse vraiment exacte à la question: toutes les autres propositions utilisent un conteneur "presque identique", mais elles oublient les volumes, env, UID, ...
Florian Klein
3
Dans mon cas, / usr / bin / sleep n'était pas disponible. J'ai eu du succès avec..."Path":"tail","Args":["-f","/dev/null"]...
nevrome
4
Les versions plus récentes de docker ont config.v2.json, où vous devrez changer soit Entrypointou Cmd.
user60561
20

Ajoutez un chèque en haut de votre script Entrypoint

Docker a vraiment besoin de l'implémenter en tant que nouvelle fonctionnalité, mais voici une autre option de contournement pour les situations dans lesquelles vous avez un Entrypoint qui se termine après un succès ou un échec, ce qui peut rendre le débogage difficile.

Si vous n'avez pas encore de script Entrypoint, créez-en un qui exécute les commandes dont vous avez besoin pour votre conteneur. Ensuite, en haut de ce fichier, ajoutez ces lignes à entrypoint.sh:

# Run once, hold otherwise
if [ -f "already_ran" ]; then
    echo "Already ran the Entrypoint once. Holding indefinitely for debugging."
    cat
fi
touch already_ran

# Do your main things down here

Pour garantir le catmaintien de la connexion, vous devrez peut-être fournir un ATS. J'exécute le conteneur avec mon script Entrypoint comme ceci:

docker run -t --entrypoint entrypoint.sh image_name

Cela entraînera l'exécution du script une fois, créant un fichier qui indique qu'il a déjà été exécuté (dans le système de fichiers virtuel du conteneur). Vous pouvez ensuite redémarrer le conteneur pour effectuer le débogage:

docker start container_name

Lorsque vous redémarrez le conteneur, le already_ranfichier est trouvé, ce qui provoque le blocage du script Entrypoint cat(qui attend juste indéfiniment une entrée qui ne viendra jamais, mais maintient le conteneur en vie). Vous pouvez ensuite exécuter une bashsession de débogage :

docker exec -i container_name bash

Pendant l'exécution du conteneur, vous pouvez également supprimer already_ranet exécuter manuellement le entrypoint.shscript pour le réexécuter, si vous avez besoin de déboguer de cette façon.

Ethan T
la source
3
De plus, vous pouvez faire fonctionner le point d'entrée /bin/shau lieu de cat- alors vous pouvez toujours entrer simplement en redémarrant. Votre solution est géniale!
Danny Dulai
4

Mon problème:

  • J'ai commencé un conteneur avec docker run <IMAGE_NAME>
  • Et puis ajouté des fichiers à ce conteneur
  • Ensuite, j'ai fermé le conteneur et j'ai essayé de le redémarrer avec la même commande que ci-dessus.
  • Mais quand j'ai vérifié les nouveaux fichiers, ils manquaient
  • quand je courais, docker ps -aje pouvais voir deux conteneurs.
  • Cela signifie qu'à chaque fois que j'exécute une docker run <IMAGE_NAME>commande, une nouvelle image est créée

Solution: pour travailler sur le même conteneur que vous avez créé lors de la première exécution, procédez comme suit

  • docker ps pour obtenir le conteneur de votre conteneur
  • docker container start <CONTAINER_ID> pour démarrer le conteneur existant
  • Ensuite, vous pouvez continuer d'où vous êtes parti. par exempledocker exec -it <CONTAINER_ID> /bin/bash
  • Vous pouvez alors décider d'en créer une nouvelle image
Amit Dudhbade
la source
Cela ne répond pas à la question. L'OP veut savoir comment redémarrer le conteneur mais avec des arguments différents de ceux utilisés dansdocker run <containerID>
CodeBlooded
2

J'ai pris la réponse de @ Dmitriusan et en ai fait un alias:

alias docker-run-prev-container = 'prev_container_id = "$ (docker ps -aq | head -n1)" && docker commit "$ prev_container_id" "prev_container / $ prev_container_id" && docker run -it --entrypoint = bash "prev_container / $ prev_container_id "'

Ajoutez ceci dans votre ~/.bashrcfichier d'alias et vous aurez un nouvel docker-run-prev-containeralias astucieux qui vous déposera dans un shell dans le conteneur précédent.

Utile pour le débogage a échoué docker builds.

Dean plutôt
la source
2

Ce n'est pas exactement ce que vous demandez, mais vous pouvez l'utiliser docker exportsur un conteneur arrêté si tout ce que vous voulez est d'inspecter les fichiers.

mkdir $TARGET_DIR
docker export $CONTAINER_ID | tar -x -C $TARGET_DIR
Lars Christian Jensen
la source
1

Il n'a pas été spécifié si le conteneur se termine, mais seulement que votre code se bloque et que vous devez voir ce qui se passe dans le conteneur. S'il ne se termine pas, voici une autre solution potentielle.

Obtenez l'ID du conteneur avec docker ps

docker exec -it 665b4a1e17b6 /bin/sh

Si le point d'entrée est défini sur quelque chose de problématique, il peut également être ignoré comme suggéré dans la réponse de Dmitriusan. Il convient également de noter que vous pouvez attacher à n'importe quel conteneur en cours d'exécution avecdocker attach . Tant de solutions différentes solutions. Je ne vois tout simplement pas la nécessité de s'engager sur l'image. Cela semble inutile.

Docs pour Docker exec - https://docs.docker.com/engine/reference/commandline/exec/

Documents pour Docker attach - https://docs.docker.com/engine/reference/commandline/attach/

deadbabykitten
la source
-12

Je suis en fait en désaccord avec ces deux réponses. Si vous voulez simplement voir ce qu'il y a dans le conteneur, vous pouvez exécuter cette commande pour obtenir un shell. Pas besoin de changer le point d'entrée du tout ou des configurations.

docker run -it <image_name> bash
deadbabykitten
la source
12
Cela ne fonctionne pas car l'op pose des questions sur un conteneur, pas sur une image.
Peter Vrabel
Je suppose que vous avez raison, mais je ne vois pas de raison de le faire. Vous pouvez diriger les journaux vers stdout et docker logs <container_id> --followvous fournirez ce dont vous avez besoin. Une autre alternative consiste à utiliser la commande ci-dessus, puis à démarrer le service de blocage sur cette image avec la même commande dans le dockerfile et à déboguer à partir de là.
deadbabykitten
4
La commande run crée un nouveau conteneur à partir d'une image. Il ne démarre pas un conteneur arrêté.
Waleed Abdulla
2
Ummm, .. n'est-ce pas le point de docker, c'est que chaque image peut être lancée exactement de la même manière? Cela nie votre argument. Il n'a PAS BESOIN de démarrer un conteneur arrêté. Tout conteneur est exactement le même, donc peu importe celui qu'il démarre ou arrête. Il essaie juste d'en inspecter le contenu. La façon la plus simple de le faire est de lancer et d'exécuter la commande ou de diriger la sortie de la commande vers les journaux. Vous venez parfois avec les solutions les plus complexes pour des problèmes simples.
deadbabykitten
-12
docker container start <CONTAINER_ID>
Oscar Calderón
la source