Se connecter à un conteneur
Objectif de cet atelier pratique
- Ouvrir un shell interactif sur un conteneur en état d'exécution.
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 :
- 
L'option -itest requise si vous voulez disposer d'un shell interactif.
- 
Nous n'avons pas utilisé l'option -dpour 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ôted724f090a8cfdu 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 et nous retrouvons l'invite de l'hôte :
Jetons un œil sur docker ps :
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.
Il 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/bashn'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.
Un shell réduit au strict minimum
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.
Ouvrir un shell avec bash ou sh
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 :
Et avec le shell rudimentaire sh :
Pensez à utiliser l'option -it
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 :
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
Une modification éphémère
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 :
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.
À vous de jouer !
- 
Lancez un conteneur basé sur l'image redisde manière à vous connecter directement au shell Bash du conteneur. Nommez le conteneurshell_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_redisbasé 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 shplutôt que Bash.
- 
Quittez le conteneur. 
- 
Arrêtez-le et supprimez-le. 
