Ma première application¶
Concepts¶
Le but ici est de lancer une application microservice web Jupyter Notebook en tâche de fond.
Application en arrière plan¶
Afin qu'un conteneur tourne en arrière plan il faut utiliser l'option -d
(--detach
) :
Publication de ports¶
Un jupyter notebook étant une application web, il est nécessaire de relier un port réseau du conteneur à un port de la machine hôte. On parle alors de port mapping ou de publication de ports en français.
En effet, lorsqu'un conteneur est créé, celui-ci n'expose par défaut aucun de ces ports au monde extérieur. En d'autres termes, si le contenur contient une application "réseau" (web, ssh, dns...), cette dernière n'est pas accessible depuis l'extérieur du conteneur. Il faut alors utiliser l'option -p
ou (--publish
) pour la rendre accessible à l'extérieur de Docker, tel que :
Voici, sous forme d'exemples, les explications de la commande précédente :
Options | Explications |
---|---|
-p 8080:80 (ou -p 8080:80/tcp ) |
Relie le port 8080 de la machine hôte au port 80 dans le conteneur en TCP (par défaut) |
-p 8080:80/udp |
Relie le port 8080 de la machine hôte au port 80 dans le conteneur en UDP |
-p 192.168.1.100:8080:80 |
Relie le port 8080 de la machine hôte avec l'IP 192.168.1.100 au port 80 dans le conteneur en TCP |
-p 8080:80/tcp -p 8080:80/udp |
Relie le port 8080 de la machine hôte au port 80 dans le conteneur en TCP, et relie le port 8080 de la machine hôte au port 80 dans le conteneur en UDP |
Remarques
- L'option
-p 8080:80
est équivalente à-p 0.0.0.0:8080:80
, ce qui signifie que Docker va publier le port80
du conteneur sur le port8080
de toutes les interfaces réseau de la machine hôte; - La remarque précédente s'applique de la même manière à
-p 8080:80/udp
qui est équivalent à-p 0.0.0.0:8080:80/udp
.
Danger
La publication d'un port d'un conteneur peut représenter un risque en terme de sécurité puisque celui-ci devient accessible depuis l'extérieur.
Pour des raisons de sécurité, notamment pour les ordinateurs portables connectés sur un réseau public, il est important de limiter les connexions à localhost
(127.0.0.1
) de façon à ce que seule la machine hôte puisse accéder au port publié. Par exemple :
Application avec un Jupyter¶
-
Afin de réaliser cet exercice, téléchargez tout d'abord l'image
jupyter/base-notebook
basée sur Ubuntu (il existe d'autres images plus complète comme lajupyter/minimal-notebook
ou lajupyter/scipy-notebook
qui est beaucoup plus lourde) :Remarque
Si le tag (ici
lab-4.0.7
) est omis, l'image téléchargée sera celle avec le tag par défaut :latest
; dans ce cas, il n'est pas nécessaire de le spécifier dans la commandedocker run
. -
Lancez maintenant le conteneur jupyter notebook en tache de fond, de façon à ce que le port
8888
(port sur lequel il écoute dans le conteneur) soit publié sur le port de votre choix (> 1023
) sur la machine hôte; -
Connectez-vous sur l'interface web du jupyter notebook.
Note
Pour la dernière question, vous aurez besoin de réaliser un tunnel
Cela vous permettra de vous connecter au notebook à l'adresse :ssh
si vous réalisez ce tutoriel sur un serveur distant ayant la plus part de ses ports fermés. Pour cela, ouvrir un autre terminal et taper :http://127.0.0.1:<port_choisi>
.Solution
Le choix le plus "judicieux" (mais pas obligatoire) était de faire correspondre le port
En adaptant le tunnel8888
du Jupyter Notebook dans le conteneur au port8888
sur la machine hôte:ssh
en conséquence : nous pouvons nous connecter au Jupyter Notebook à l'adresse suivante: http://127.0.0.1:8888.
Une fois sur la page de connexion, il est nécessaire de rentrer un token d'identification afin de pouvoir se connecter au notebook.
Il faut pour cela lire la sortie standarde (STDOUT
) et la sortie d'erreur (STDERR
) à l'aide de la commande docker logs
:
docker logs <nom du conteneur>
docker logs -f <nom du conteneur> # -f (--follow) permet de suivre les logs en temps réels
-
Examinez les logs du conteneur afin de récupérer le token
Connectez-vous maintenant au notebook en cliquant sur le lien donné par la dernière commande, ouvrez un terminal dans le Jupyter Notebook et essayez :
curl -L https://gitlab.in2p3.fr/ri3/ecole-info/2023/anf-conteneurs/docker/-/raw/main/files/python_codes/hello_world.py -o hello_world.py
-
La commande
curl
n'est pas installée. Installez la dans le conteneur en vous connectant en tant qu'utilisateurroot
dans le conteneur, à l'aide de :Solution
En effet, l'utilisateur lancé par défaut dans le conteneur jupyter est
jovyan
. Pour pouvoir se connecter dans le conteneur en tant qu'un autre utilisateur (existant), il faut le préciser à l'aide de l'option-u
(--user
). -
Exécutez les programmes python de l'exemple ci-dessus. Pour cela, allez sur la page web du notebook, ouvrez un terminal et réessayez la commande :
(base) jovyan@495f0be775ce:~$ curl -L https://gitlab.in2p3.fr/ri3/ecole-info/2023/anf-conteneurs/docker/-/raw/main/files/python_codes/hello_world.py -o hello_world.py (base) jovyan@495f0be775ce:~$ curl -L https://gitlab.in2p3.fr/ri3/ecole-info/2023/anf-conteneurs/docker/-/raw/main/files/python_codes/pi.py -o pi.py (base) jovyan@495f0be775ce:~$ python hello_world.py (base) jovyan@495f0be775ce:~$ pip install numpy matplotlib (base) jovyan@495f0be775ce:~$ python pi.py
Plutôt que de devoir installer la commande curl
dans le conteneur pour télécharger les deux codes python que nous avons executés, vous pouvez essayer de monter le répertoire les contenant dans le conteneur :
docker run -d --name myjupyter \
-v python_codes/:/home/jovyan/work \
-p 127.0.0.1:8888:8888 \
jupyter/base-notebook
Remarque
Notez que le binding ne fonctionnera pas correctement si votre uid
n'est pas 1000
. Le conteneur notebook de jupyter supporte certaines options passées en tant que variables d'environnement via l'option -e
. Par exemple, pour lancer un notebook avec l'ensemble du répertoire personnel monté à l'intérieur du conteneur :
Rappelons que tout ce qui a été installé dans le conteneur (comme la commande curl
, les modules python numpy
et matplotlib
) est perdu lorsque le conteneur est détruit.
Afin de rendre les modifications pérennes, il faut intégrer les modifications directement dans l'image du conteneur.
Gérer le microservice¶
Le conteneur peut être désactivé avec :
De la même manière, il peut être démarré (redémarré) en remplaçant stop
par start
(restart
), mais le jeton d'identification sera renouvelé :
Ou en utilisant la commande kill :
En ajoutant l'option --restart always
à la commande docker run
, le conteneur est toujours redémarré s'il est arrêté. S'il est arrêté manuellement, il n'est redémarré que lorsque le démon Docker redémarre ou que le conteneur lui-même est redémarré manuellement. Cette option peut être intéressante pour une utilisation en production.
docker run -d --restart always \
-v /some/path/on/host/:/home/jovyan/work \
-p 127.0.0.1:8888:8888 \
jupyter/base-notebook