Aller au contenu

Se connecter à un conteneur Docker

Objectifs :

  • Ouvrir un shell interactif sur un conteneur en état d'exécution

  • Exécuter des commandes à l'intérieur d'un conteneur

Interagir avec un conteneur

En temps normal, on n'utilise pas SSH pour se connecter à un conteneur comme on le ferait avec une machine virtuelle, par exemple. Plutôt que de modifier un conteneur en cours d'exécution, on préférera adapter le Dockerfile correspondant pour ensuite reconstruire l'image du conteneur.

Ceci étant dit, il peut être utile dans certains cas de figure de se connecter directement à un conteneur pour savoir ce qui se passe à l'intérieur, et de le faire de manière interactive plutôt que de simplement regarder les logs ou les données générées par le conteneur.

Docker fournit la commande exec pour accéder à un conteneur en état d'exécution. Avant de faire ça, nous allons nous connecter directement au shell d'un conteneur au moment de son lancement.

Connexion avec la commande run

Pour démarrer un conteneur Apache auquel nous pouvons accéder directement via le shell au moment du lancement, nous allons utiliser la commande suivante :

$ docker run -it --name apache httpd /bin/bash
root@d724f090a8cf:/usr/local/apache2#
  • L'option -it est requise si vous voulez disposer d'un shell interactif.

  • Nous n'avons pas utilisé l'option -d pour détacher le conteneur et l'exécuter en arrière-plan. Cette fois-ci nous exécutons la commande en avant-plan.

  • Nous avons indiqué une commande à exécuter à Docker, en l'occurrence /bin/bash.

  • Une fois que la commande s'exécute, nous voyons que l'invite de commande change. C'est l'invite de l'interpréteur de commandes Bash, qui nous affiche l'utilisateur root, le nom d'hôte d724f090a8cf du conteneur suivi de deux-points, puis le répertoire courant, en l'occurrence /usr/local/apache2.

Une fois que nous sommes dans le conteneur, nous pouvons exécuter n'importe quelle commande disponible dans le shell Bash :

root@d724f090a8cf:/usr/local/apache2# pwd
/usr/local/apache2
root@d724f090a8cf:/usr/local/apache2# ls
bin  build  cgi-bin  conf  error  htdocs  icons  include  logs  modules

Pour quitter le conteneur, nous pouvons utiliser le raccourci Ctrl+D ou la commande exit :

root@d724f090a8cf:/usr/local/apache2# exit
exit
[kikinovak@alphamule:~] $

Nous retrouvons l'invite de commande de la machine hôte.

Jetons un œil sur docker ps :

$ docker ps
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES

Le conteneur ne s'affiche pas ici, étant donné qu'il n'est plus en cours d'exécution. Cela tient au fait que nous n'avons pas fourni l'option -d pour le détacher et l'exécuter en arrière-plan.

Le conteneur a exécuté la commande que nous lui avons fournie en argument - en l'occurrence /bin/bash - et dès que nous avons quitté Bash, le conteneur s'est arrêté.

Maintenant, exécutons la commande à nouveau, mais en ajoutant l'option -d :

$ docker run -dit --name autre_apache httpd /bin/bash
96e278c968a813c01194424236e588cb5e9284fd6d85b1d837cf04ae3e67e5d2
$ docker ps
CONTAINER ID   IMAGE     COMMAND       ...  NAMES
96e278c968a8   httpd     "/bin/bash"   ...  autre_apache
  • Cette fois-ci, le conteneur s'est immédiatement détaché, étant donné que nous avons utilisé l'option -d.

  • L'argument final /bin/bash n'a pas vraiment de sens ici. Le conteneur est certes en état d'exécution, mais nous n'y sommes pas connectés. Nous ne pouvons donc pas taper des commandes dans l'interpréteur de commandes Bash.

Modérez vos attentes en matière de shells avec les conteneurs Docker. Beaucoup de conteneurs sont basés sur Alpine Linux, une distribution Linux minimaliste qui permet de construire des conteneurs très réduits. Alpine n'utilise pas une version complète de Bash, vous devez donc ajouter /bin/sh pour accéder à une invite. D'autres distributions procèdent de même. Certaines utilisent un lien symbolique /bin/bash vers un shell sh à l'ancienne. Quoi qu'il en soit, attendez-vous à ne pas pouvoir accéder à toutes les commandes que vous utilisez habituellement, à la complétion automatique et l'historique des commandes, etc.

Voici une petite astuce, qui est juste une manière différente de faire les choses. Un peu plus haut, nous avons fourni le chemin complet /bin/bash à notre commande run, ce qui est la façon orthodoxe de procéder. Or, vous pouvez très bien passer bash ou sh comme dernier paramètre. Ce qui fonctionnera tant que la variable d'environnement PATH interne est configurée pour le conteneur et que la commande bash ou sh se trouve dans le PATH, ce qui est généralement le cas.

Connexion avec la commande exec

Passons à la commande docker exec. Comme nous venons de le voir, cela ne sert pas à grand-chose de spécifier la commande /bin/bash à un conteneur qui sera détaché immédiatement. Ce qui veut dire que nous avons besoin d'un autre moyen pour accéder au shell d'un conteneur en cours d'exécution. Et c'est là où nous allons utiliser la commande exec :

$ docker run -dit --name shelltest httpd
373a25810b747e6f8198cedd40974cad11d007aea68dd5f889fedbda869e0d9a
$ docker ps
...
$ docker exec -it shelltest /bin/bash
root@373a25810b74:/usr/local/apache2# exit

Voyons ce que cela donne si nous ne fournissons pas le chemin complet vers le shell Bash :

$ docker exec -it shelltest bash
root@373a25810b74:/usr/local/apache2# exit

Et avec le shell rudimentaire sh :

$ docker exec -it shelltest sh
# exit

Dans ce contexte, une erreur fréquente consiste à oublier les options -it. Dans ce cas, le shell va s'exécuter et s'arrêter aussitôt.

Exécuter des commandes

Vous vous en doutez probablement, mais la sous-commande exec ne se limite pas au lancement d'un shell. Elle sait faire bien plus que ça. En principe, elle nous permet d'exécuter toutes les commandes disponibles dans un conteneur.

La commande ci-dessous crée un fichier vide coucou.txt dans un conteneur en passant par exec :

$ docker run -dit --name execution httpd
c7bf797bd79176fbc6c4dd99b0a0b27bd6aa3175442df0e8819e7e16cdab07e2
$ docker ps
...
$ docker exec -d execution touch /root/coucou.txt
$ docker exec -it execution bash
root@c7bf797bd791:/usr/local/apache2# ls /root
coucou.txt
root@c7bf797bd791:/usr/local/apache2# exit
exit

Et puisque nous pouvons exécuter n'importe quelle commande disponible dans le conteneur, nous aurions très bien pu faire ceci :

$ docker exec -it execution ls /root
coucou.txt

Tout l'intérêt des containers, c'est que ce sont des images extrêmement réduites. Ce ne sont pas des systèmes d'exploitation complets ou des installations complètes de distributions Linux. Ce qui signifie que certaines ou même la plupart des commandes que vous avec l'habitude d'utiliser au quotidien sous Linux peuvent ne pas être disponibles dans un conteneur :

$ docker exec -it execution bash
root@c7bf797bd791:/usr/local/apache2# uptime
bash: uptime: command not found
root@c7bf797bd791:/usr/local/apache2# man
bash: man: command not found
root@c7bf797bd791:/usr/local/apache2# locate
bash: locate: command not found
root@c7bf797bd791:/usr/local/apache2# vim
bash: vim: command not found
root@c7bf797bd791:/usr/local/apache2# vi
bash: vi: command not found
root@c7bf797bd791:/usr/local/apache2# nano
bash: nano: command not found

Si vous voulez qu'une commande soit disponible dans votre conteneur, vous pouvez très bien l'installer. L'image officielle httpd:latest est basée sur Debian, nous pouvons donc utiliser les gestionnaires de paquets apt-get ou apt pour installer un ou plusieurs paquets :

root@c7bf797bd791:/usr/local/apache2# apt update
root@c7bf797bd791:/usr/local/apache2# apt install vim
root@c7bf797bd791:/usr/local/apache2# vim

L'installation d'un paquet modifie le conteneur en cours d'exécution, mais pas l'image sur laquelle ce conteneur est basé. Si vous voulez qu'un logiciel soit disponible dans les nouveaux conteneurs, il vous faudra recréer l'image en conséquence.

L'absence de la commande ps dans certains conteneurs peut s'avérer gênante :

root@c7bf797bd791:/usr/local/apache2# ps
bash: ps: command not found

Dans ce cas, il vaut mieux utiliser la commande docker top, qui permet d'afficher les processus en cours à l'intérieur d'un conteneur :

root@c7bf797bd791:/usr/local/apache2# exit
exit 
# docker top execution
UID   PID  PPID  C  STIME  TTY    TIME      CMD
root  2414 2396  0  09:52  pts/0  00:00:00  httpd -DFOREGROUND
bin   2440 2414  0  09:52  pts/0  00:00:00  httpd -DFOREGROUND
bin   2441 2414  0  09:52  pts/0  00:00:00  httpd -DFOREGROUND
bin   2442 2414  0  09:52  pts/0  00:00:00  httpd -DFOREGROUND

Ici, nous voyons quatre processus httpd en cours à l'intérieur du conteneur nommé execution.

Exercice

  • Lancez un conteneur basé sur l'image redis de manière à vous connecter directement au shell Bash du conteneur. Nommez le conteneur shell_redis.

  • Quelle est la version du shell Bash fourni par le conteneur ?

  • Quittez le shell du conteneur.

  • Vérifiez s'il est bien arrêté.

  • Supprimez-le.

  • Lancez un autre conteneur exec_redis basé sur cette même image. Cette fois-ci, le conteneur devra tourner en arrière-plan.

  • Vérifiez si le conteneur tourne en arrière-plan comme prévu.

  • Connectez-vous au shell Bash du conteneur en état d'exécution.

  • Affichez la version du shell Bash.

  • Quittez le conteneur.

  • Reconnectez-vous sans spécifier le chemin complet vers le shell Bash.

  • Quittez le conteneur en utilisant une autre manière que celle que vous venez d'utiliser.

  • Vérifiez si le conteneur tourne toujours.

  • Reconnectez-vous une dernière fois au conteneur. Cette fois-ci, utilisez le shell rudimentaire sh plutôt que Bash.

  • Quittez le conteneur.

  • Arrêtez-le et supprimez-le.


La rédaction de ces cours demande du temps et des quantités significatives de café espresso. Vous appréciez cette formation ? Offrez un café au formateur en cliquant sur la tasse.