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ôted724f090a8cf
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 shellsh
à 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 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_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.