Semaine 8 — Les commandes de base de Docker¶
Durée estimée : 45 min · Prérequis : Docker : images et conteneurs
Objectifs d'apprentissage¶
- Lancer un conteneur avec
docker run, et choisir ses options principales. - Suivre un conteneur dans son cycle de vie : créé, en marche, arrêté, supprimé.
- Rendre un service web d'un conteneur accessible depuis votre poste.
- Lire les journaux d'un conteneur et y lancer une commande.
1. La forme d'une commande Docker¶
Toutes les commandes Docker ont la même forme :
docker run -d --name web -p 8080:80 nginx
│ │ └──────── options ──────┘ └── image
│ └── l'action
└── le programme
Les options de Docker se placent avant le nom de l'image. Tout ce qui suit le nom de l'image est transmis au programme du conteneur, et non à Docker : docker run nginx -d passe l'argument -d à nginx, et le conteneur ne s'exécute pas en arrière-plan.
Astuce
Chaque commande accepte --help : docker run --help, docker ps --help. Les options utilisées dans ce cours sont résumées à la section 6.
2. Le cycle de vie d'un conteneur¶
Un conteneur passe par quelques états. docker ps -a les affiche dans la colonne STATUS.
stateDiagram-v2
direction LR
[*] --> Created: docker create
Created --> Up: docker start
[*] --> Up: docker run
Up --> Exited: docker stop, ou fin du programme
Exited --> Up: docker start
Exited --> [*]: docker rm
Up --> [*]: docker rm -f
| État affiché | Ce que ça veut dire |
|---|---|
Created |
Le conteneur existe, mais son programme n'a jamais été lancé. |
Up 3 minutes |
Le programme tourne depuis trois minutes. |
Exited (0) 2 seconds ago |
Le programme s'est terminé normalement. Le 0 est son code de sortie : zéro veut dire « tout s'est bien passé ». |
Exited (1) ... ou un autre nombre |
Le programme s'est terminé sur une erreur. Lisez ses journaux avec docker logs. |
docker run enchaîne docker pull (si l'image est absente), docker create et docker start. C'est la commande utilisée en pratique pour créer un conteneur.
Un conteneur arrêté (Exited) conserve sa couche inscriptible et ses paramètres. docker start le relance dans cet état. docker rm le supprime définitivement, avec sa couche inscriptible.
3. Lancer un conteneur : docker run¶
Au premier plan ou en arrière-plan¶
Par défaut, docker run attache le terminal au conteneur : la sortie du programme s'affiche, et l'invite revient quand il se termine. Pour un serveur, qui ne se termine pas, le terminal reste occupé.
L'option -d (detached) exécute le conteneur en arrière-plan. Docker affiche l'identifiant du conteneur créé et rend l'invite immédiatement.
Donner un nom¶
Sans l'option --name, Docker génère un nom aléatoire, comme angry_tesla. Nommer le conteneur permet de le désigner de façon prévisible dans les commandes suivantes :
Un nom est unique sur l'hôte. Toutes les commandes acceptent le nom ou l'identifiant ; pour l'identifiant, les premiers caractères suffisent s'ils ne sont pas ambigus : docker stop 197a.
Une session interactive¶
L'option -i garde l'entrée standard ouverte, et -t alloue un pseudo-terminal. Combinées en -it, elles permettent d'utiliser un programme interactif, comme un shell, dans le conteneur :
Le shell s'exécute dans un nouveau conteneur Alpine. exit termine le shell, qui est le programme principal : le conteneur s'arrête.
Suppression automatique¶
L'option --rm supprime le conteneur dès qu'il s'arrête. Elle convient aux conteneurs lancés pour une seule commande :
Passer une variable d'environnement¶
L'option -e définit une variable d'environnement pour le programme du conteneur. C'est le moyen habituel de paramétrer une image sans la modifier : mot de passe, adresse d'une base de données, langue.
À la semaine 7, -e DB_HOST=10.70.8E.10 indiquait ainsi au site d'Aria l'adresse de sa base de données.
4. Publier un port : -p¶
Le réseau des conteneurs¶
À son installation, Docker crée dans l'hôte un bridge nommé docker0, sur le réseau privé 172.17.0.0/16. C'est le même principe que le bridge vmbr1 de la semaine 3 : un commutateur logiciel interne. Chaque conteneur reçoit une interface branchée sur ce bridge et une adresse dans ce réseau, par exemple 172.17.0.2. L'hôte sert de passerelle et fait la traduction d'adresses (NAT) vers l'extérieur.
Les conteneurs peuvent donc sortir vers Internet, mais aucune machine extérieure ne peut joindre le réseau 172.17.0.0/16. nginx écoute sur le port 80 de son conteneur, et ce port n'est pas accessible depuis votre poste.
La publication¶
L'option -p publie un port : Docker redirige vers un port du conteneur les connexions reçues sur un port de l'hôte.
-p 8080:80
│ └── le port du conteneur, où nginx écoute
└── le port de l'hôte, où arrivent les connexions
L'ordre est toujours hôte:conteneur.
flowchart LR
P["Poste de travail"]
subgraph VM["VM docker · 10.70.#.31"]
PV(["port 8080"])
B["bridge docker0<br/>172.17.0.1"]
subgraph C["conteneur web · 172.17.0.2"]
N["nginx, port 80"]
end
end
P -- "http://10.70.#.31:8080" --> PV
PV -- "redirection" --> B
B --> N
Le port du conteneur est déterminé par l'application : 80 pour nginx, 3306 pour MySQL. Le port de l'hôte est libre. Plusieurs conteneurs issus de la même image peuvent donc coexister, à condition que chacun soit publié sur un port différent de l'hôte :
docker run -d --name site1 -p 8081:80 nginx
docker run -d --name site2 -p 8082:80 nginx
docker run -d --name site3 -p 8083:80 nginx
Les trois nginx écoutent sur le port 80 sans conflit, puisque chacun a sa propre interface et sa propre adresse sur docker0. Seul le port de l'hôte doit être unique.
5. Observer et gérer les conteneurs¶
Lister : docker ps¶
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
197ac5e25f57 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp web
docker ps n'affiche que les conteneurs en cours d'exécution. L'option -a (all) ajoute les conteneurs arrêtés. Un conteneur qui vient d'être lancé et qui n'apparaît pas dans docker ps s'est généralement arrêté : docker ps -a indique son état et son code de sortie.
La colonne PORTS reprend la publication : 0.0.0.0:8080->80/tcp signifie que le port 8080, sur toutes les adresses IPv4 de l'hôte, est redirigé vers le port 80 du conteneur. Sans publication, la colonne n'indique que le port déclaré par l'image, sans flèche : 80/tcp.
Lire les journaux : docker logs¶
Docker conserve tout ce que le programme principal écrit sur sa sortie standard et sa sortie d'erreur. docker logs l'affiche :
Avec -f (follow), l'affichage continue au fil des nouvelles lignes, comme tail -f. Ctrl+C interrompt l'affichage, pas le conteneur.
docker logs est la première commande de diagnostic : un conteneur qui s'arrête de lui-même y écrit presque toujours la cause de son arrêt.
Arrêter, redémarrer, supprimer¶
docker stop web # arrête le programme ; le conteneur passe à Exited
docker start web # le relance, avec son contenu
docker rm web # le supprime ; il doit être arrêté
docker rm -f web # l'arrête et le supprime d'un coup
Lancer une commande dans un conteneur en marche : docker exec¶
docker exec lance un processus supplémentaire dans un conteneur en cours d'exécution, avec les mêmes namespaces que son programme principal :
Avec -it et un shell, on obtient une session interactive dans le conteneur :
exit termine ce shell, mais le conteneur continue de s'exécuter : son programme principal, nginx, n'est pas concerné.
docker run crée, docker exec s'ajoute
docker run -it nginx bash crée un nouveau conteneur dont le programme principal est bash à la place de nginx : aucun serveur web n'y est lancé. Pour agir dans un conteneur existant, la commande est docker exec.
Gérer les images¶
docker images # liste les images sur le disque de la VM
docker pull alpine # télécharge une image sans lancer de conteneur
docker rmi alpine # supprime une image (aucun conteneur ne doit en dépendre)
6. Aide-mémoire¶
| Action | Commande |
|---|---|
| Lancer un conteneur en arrière-plan | docker run -d --name NOM IMAGE |
| Lancer un conteneur avec un shell interactif | docker run -it IMAGE sh |
| Exécuter une commande ponctuelle, sans conserver le conteneur | docker run --rm IMAGE COMMANDE |
| Publier un port | docker run -d -p PORT_HÔTE:PORT_CONTENEUR IMAGE |
| Définir une variable d'environnement | docker run -e VARIABLE=valeur IMAGE |
| Lister les conteneurs en cours d'exécution | docker ps |
| Lister tous les conteneurs | docker ps -a |
| Lire les journaux | docker logs NOM (ou -f pour suivre) |
| Ouvrir un shell dans un conteneur en cours d'exécution | docker exec -it NOM sh |
| Arrêter / relancer | docker stop NOM / docker start NOM |
| Supprimer | docker rm NOM (ou rm -f s'il tourne) |
| Voir les images | docker images |
| Supprimer une image | docker rmi IMAGE |
| Supprimer les conteneurs arrêtés / les images inutilisées | docker container prune / docker image prune -a |
Pièges fréquents¶
- Placer une option après l'image.
docker run nginx -p 8080:80ne publie aucun port : l'argument est transmis à nginx. - Inverser les ports.
-p 80:8080redirige le port 80 de l'hôte vers le port 8080 du conteneur, où rien n'écoute. L'ordre esthôte:conteneur. - Supposer qu'un
docker runen échec ne laisse rien. Lorsquedocker runéchoue surport is already allocated, le conteneur a déjà été créé : il reste à l'étatCreatedet son nom est réservé. Il faut le supprimer avecdocker rmavant de relancer la commande. - Utiliser
docker runpour redémarrer un conteneur.docker runcrée toujours un nouveau conteneur.docker startrelance un conteneur existant. - Laisser s'accumuler les conteneurs arrêtés. Ils réservent leur nom et occupent de l'espace disque.
docker ps -ales liste,docker container pruneles supprime.
Vérification des acquis¶
Question 1¶
Vous voulez que le site d'un conteneur nginx soit visible à l'adresse http://10.70.4.31:9000. Quelle option utilisez-vous ?
- a)
-p 80:9000 - b)
-p 9000:80 - c)
-p 9000
Voir la réponse
**b) `-p 9000:80`** Le port de l'hôte, où arrivent les connexions, est à gauche : `9000`. Le port du conteneur, où nginx écoute, est à droite : `80`. Le choix a) inverse les deux : il redirige le port 80 de l'hôte vers le port 9000 du conteneur, où nginx n'écoute pas.Question 2¶
Vous tapez docker run -d --name test alpine, puis docker ps. Le conteneur test n'apparaît pas. Pourquoi ?
- a) L'image
alpinen'a pas été téléchargée. - b) Le programme par défaut d'Alpine est un shell. Sans entrée standard ouverte (
-i), il n'a rien à lire et se termine aussitôt, ce qui arrête le conteneur. - c)
-dmasque les conteneurs dans la liste.
Voir la réponse
**b) Le shell s'est terminé aussitôt.** Le programme principal de l'image `alpine` est `sh`. Sans `-i`, son entrée standard est fermée : il lit une fin de fichier et se termine avec le code 0. `docker ps -a` montre le conteneur à l'état `Exited (0)`. Le choix a) est faux : une image absente est téléchargée automatiquement, ou la commande échoue avec un message d'erreur.Question 3¶
Vous avez lancé un conteneur web à partir de nginx. Vous voulez lister les fichiers de son site sans l'arrêter. Quelle commande utilisez-vous ?
- a)
docker run -it web ls /usr/share/nginx/html - b)
docker exec web ls /usr/share/nginx/html - c)
docker start web ls /usr/share/nginx/html
Voir la réponse
**b) `docker exec web ls /usr/share/nginx/html`** `docker exec` lance un processus supplémentaire dans un conteneur en cours d'exécution, sans affecter son programme principal. Le choix a) cherche une **image** nommée `web` : `docker run` prend toujours une image en argument, jamais un conteneur.Question 4¶
Vous arrêtez un conteneur avec docker stop, puis vous le relancez avec docker start. Les fichiers que vous aviez modifiés dans le conteneur sont-ils encore là ?
- a) Oui : un conteneur arrêté garde son contenu jusqu'à ce qu'il soit supprimé.
- b) Non : chaque démarrage repart de l'image.
Voir la réponse
**a) Oui.** `docker stop` arrête le programme principal, mais le conteneur reste sur le disque avec sa couche inscriptible. `docker start` relance ce même conteneur. `docker rm` supprime la couche inscriptible. Un conteneur créé ensuite avec `docker run` part de l'image, sans les modifications. La conservation des données au-delà de la vie d'un conteneur, avec les **volumes**, est traitée à la semaine 10.Pour aller plus loin¶
- docker container run, la référence complète de
docker runet de toutes ses options. - Publishing and exposing ports, dans la documentation de Docker.