Aller au contenu

Exercice 2 — Préparer sa VM et lancer un premier conteneur

Durée : ~45 min · Individuel · Théorie associée : Docker : images et conteneurs

Objectif

Vous avez construit votre propre VM Docker sur votre serveur, et vous y avez lancé votre premier conteneur en sachant ce que fait chaque étape.

Prérequis

  • Votre serveur Proxmox de la semaine 2, accessible à https://10.70.44.#:8006. Le # est votre numéro de serveur dans le tableau de la semaine 2.
  • Le nœud a accès à Internet depuis son Shell.

Vous travaillez seul, sur votre propre serveur. Dans tout l'exercice, remplacez # par votre numéro de serveur.

VM ID Nom Adresse
731 docker 10.70.#.31/16

Exemple : sur le serveur S04, la VM prend l'adresse 10.70.4.31. Les captures montrent ce serveur.

Les étapes 1 à 10 reprennent le template de l'exercice 2 de la semaine 4. La différence : la VM n'est pas convertie en template, et son snippet installe Docker.

Étape 1 — Autoriser les snippets sur le stockage local

Allez dans Datacenter > Storage, sélectionnez local et cliquez sur Edit. Dans la liste Content, ajoutez Snippets sans retirer les autres types. Si Snippets est déjà sélectionné, cliquez sur Cancel.

La fenêtre d'édition du stockage local avec Snippets sélectionné en plus des autres types de contenu

Étape 2 — Télécharger l'image cloud

Ouvrez le Shell du nœud.

Bash
cd /var/lib/vz/template/iso
Bash
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2
Bash
ls -lh debian-13-genericcloud-amd64.qcow2

Le fichier fait environ 330 Mo. Si wget a créé un second fichier debian-13-genericcloud-amd64.qcow2.1, l'image était déjà là : supprimez la copie avec rm debian-13-genericcloud-amd64.qcow2.1.

ls -lh affiche debian-13-genericcloud-amd64.qcow2, de 326 Mo

Étape 3 — Écrire le snippet Docker

Bash
nano /var/lib/vz/snippets/docker.yaml

Écrivez exactement ceci :

YAML
#cloud-config
packages:
  - qemu-guest-agent
  - docker.io
  - curl
runcmd:
  - systemctl enable --now qemu-guest-agent
  - systemctl enable --now docker
  - usermod -aG docker etudiant

C'est le snippet de la semaine 4, avec deux paquets de plus : docker.io installe Docker, et la dernière ligne ajoute le compte etudiant au groupe docker. Vous verrez à l'étape 12 à quoi sert ce groupe.

Étape 4 — Créer la VM vide

Bash
qm create 731 --name docker --memory 2048 --cores 2 --cpu x86-64-v2-AES --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-single --ostype l26

La VM 731 apparaît dans l'arborescence, sans disque.

Étape 5 — Importer l'image comme disque

Bash
qm set 731 --scsi0 local-lvm:0,import-from=/var/lib/vz/template/iso/debian-13-genericcloud-amd64.qcow2

Proxmox crée le volume vm-731-disk-0 et y recopie l'image. Le système est déjà dedans : il n'y a rien à installer. La copie prend de une à plusieurs minutes. Attendez la ligne successfully created disk et le retour de l'invite.

La copie atteint 100 %, puis scsi0: successfully created disk 'local-lvm:vm-731-disk-0,size=3G'

Étape 6 — Agrandir le disque

Bash
qm disk resize 731 scsi0 20G

Les images Docker prennent vite de la place. Cloud-init agrandira le système de fichiers au premier démarrage.

Étape 7 — Ajouter le lecteur Cloud-Init

Bash
qm set 731 --ide2 local-lvm:cloudinit

C'est le lecteur dans lequel Proxmox dépose le compte, l'adresse et le snippet de la VM.

Étape 8 — Régler le démarrage et la console

Bash
qm set 731 --boot order=scsi0
Bash
qm set 731 --serial0 socket
Bash
qm set 731 --agent enabled=1

Ce sont les mêmes réglages qu'à la semaine 4. Le port série rend possible la console xterm.js de l'étape 11.

Étape 9 — Rattacher le snippet

Bash
qm set 731 --cicustom "vendor=local:snippets/docker.yaml"

La forme vendor= ajoute le snippet à ce que Proxmox génère. Les champs du panneau Cloud-Init de l'étape suivante restent donc utilisés.

Étape 10 — Remplir le panneau Cloud-Init

Sélectionnez la VM 731 dans l'arborescence et ouvrez son panneau Cloud-Init. Remplissez quatre lignes avec le bouton Edit.

Ligne Valeur
User etudiant
Password Motdepasse123!
DNS servers 9.9.9.9
IP Config (net0) IPv4 Static, 10.70.#.31/16, passerelle 10.70.0.1

La fenêtre Edit: Network Config : IPv4 statique 10.70.4.31/16, passerelle 10.70.0.1

Le panneau Cloud-Init de la VM 731 : utilisateur etudiant, DNS 9.9.9.9, IP Config ip=10.70.4.31/16,gw=10.70.0.1

Étape 11 — Démarrer la VM et s'y connecter

Cliquez sur Start. Attendez deux ou trois minutes : au premier démarrage, cloud-init télécharge et installe Docker.

Ouvrez ensuite la console avec la flèche à côté de Console, puis xterm.js. Cette console accepte le copier-coller, ce qui vous évitera de retaper les commandes. Connectez-vous avec etudiant / Motdepasse123!.

Le menu déroulant du bouton Console : noVNC, SPICE et xterm.js

Étape 12 — Vérifier que vous avez le droit de parler à Docker

Bash
groups
Texte
etudiant adm dialout cdrom floppy sudo audio dip video plugdev docker

Cherchez docker à la fin de la ligne. Les membres du groupe docker peuvent utiliser Docker sans taper sudo devant chaque commande. C'est la dernière ligne du snippet de l'étape 3 qui vous y a ajouté.

Si docker n'apparaît pas, c'est que cloud-init vous a ajouté au groupe après votre connexion. Tapez exit, puis reconnectez-vous : le groupe est lu à chaque connexion.

Le groupe docker vaut le compte root

Un membre du groupe docker peut lancer un conteneur qui lit et modifie n'importe quel fichier de la VM. Sur un vrai serveur, on n'y met que les administrateurs.

La console xterm.js : groups affiche docker à la fin de la ligne

Étape 13 — Vérifier le client et le démon

Bash
docker version
Texte
Client:
 Version:           26.1.5+dfsg1
 API version:       1.45
 ...

Server:
 Engine:
  Version:          26.1.5+dfsg1
  API version:      1.45 (minimum version 1.24)
  ...

Repérez les deux parties. Client est la commande docker que vous venez de taper. Server est la réponse du démon dockerd, qui tourne en permanence dans la VM. Les deux répondent : tout est en place.

La console : docker version affiche les parties Client et Server, en version 26.1.5+dfsg1

Étape 14 — Lancer votre premier conteneur

Bash
docker run hello-world
Texte
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete
Digest: sha256:...
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
...

Chaque partie de la sortie correspond à une étape :

Ligne Ce qui s'est passé
Unable to find image 'hello-world:latest' locally Le démon a cherché l'image sur le disque de la VM, sans la trouver. Vous n'avez pas écrit d'étiquette : il a pris latest.
Pulling from library/hello-world Il la télécharge depuis Docker Hub. library/ désigne les images officielles.
Status: Downloaded newer image L'image est maintenant sur le disque.
Hello from Docker! et la suite Ce texte n'est pas écrit par Docker, mais par le programme du conteneur. Docker vous le transmet.

Les quatre étapes numérotées du message correspondent à celles de la section 9 de la note.

La console : le premier docker run hello-world télécharge l'image, puis affiche Hello from Docker!

Étape 15 — Le relancer

Bash
docker run hello-world

Le même message s'affiche, mais les quatre premières lignes ont disparu, et la réponse est instantanée. L'image était déjà sur le disque : il n'y avait rien à télécharger.

La console : le deuxième docker run hello-world affiche directement Hello from Docker!

Étape 16 — Compter les images et les conteneurs

Bash
docker images
Texte
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    e2ac70e7319a   7 months ago   10.1kB

Une image, qui pèse 10 ko. Elle ne contient qu'un petit programme qui affiche un texte.

Bash
docker ps
Texte
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

La liste est vide : aucun conteneur ne tourne. Le programme de hello-world a affiché son texte, puis s'est terminé, et le conteneur s'est arrêté avec lui.

Bash
docker ps -a
Texte
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
873946e066ff   hello-world   "/hello"   19 seconds ago   Exited (0) 18 seconds ago             great_sutherland
3ae65f46247c   hello-world   "/hello"   35 seconds ago   Exited (0) 34 seconds ago             agitated_lederberg

Avec -a, les conteneurs arrêtés apparaissent : il y en a deux, un par docker run. Une image, deux conteneurs, chacun avec sa propre couche inscriptible. Vos identifiants et vos noms seront différents, puisque Docker les choisit au hasard.

Lisez la colonne STATUS : Exited (0) veut dire que le programme s'est terminé normalement.

La console : docker images affiche hello-world, docker ps est vide, docker ps -a affiche deux conteneurs Exited (0)

Étape 17 — Faire le ménage

Supprimez les deux conteneurs, en utilisant les noms affichés dans votre colonne NAMES :

Bash
docker rm great_sutherland agitated_lederberg

Vérifiez avec docker ps -a : la liste est vide. Puis docker images : l'image hello-world est toujours là. Supprimer un conteneur ne supprime pas son image.

La console : docker rm supprime les deux conteneurs, docker ps -a est vide, l'image hello-world reste

Vérification finale

  • docker version affiche les parties Client et Server, sans sudo
  • docker images affiche l'image hello-world
  • docker ps -a n'affiche plus aucun conteneur

Question 1

Au premier docker run hello-world, Docker a téléchargé l'image. Au deuxième, non. Pourquoi ?

Voir la réponse Au premier lancement, l'image n'était pas sur le disque de la VM : le démon l'a téléchargée depuis Docker Hub, puis il l'a gardée. Au deuxième, il l'a trouvée sur le disque et a directement créé le conteneur. C'est pourquoi un `docker run` est lent la première fois, et presque instantané ensuite.

Question 2

Après vos deux docker run, docker ps n'affiche rien, mais docker ps -a affiche deux lignes. Qu'est-ce que ça veut dire ?

Voir la réponse Les deux conteneurs existent encore, mais ils sont arrêtés. `docker ps` ne montre que les conteneurs en marche. `docker ps -a` montre aussi les conteneurs arrêtés. Ils sont arrêtés parce que leur programme, `/hello`, s'est terminé après avoir affiché son texte. Un conteneur vit aussi longtemps que son programme principal.

En cas de problème

Symptôme Cause probable Correction
permission denied while trying to connect to the Docker daemon socket Votre session a commencé avant votre ajout au groupe docker exit, puis se reconnecter. Vérifier avec groups
docker: command not found cloud-init n'a pas fini d'installer Docker Attendre une minute. cloud-init status doit répondre status: done
La VM refuse de démarrer : volume 'local:snippets/docker.yaml' does not exist Le snippet n'est pas au bon endroit, ou Snippets n'est pas autorisé sur local Refaire les étapes 1 et 3
qm create répond VM 731 already exists Une VM porte déjà ce numéro sur votre serveur Supprimer l'ancienne VM si elle vous appartient. Sinon, prévenir l'enseignant : le serveur est partagé avec l'autre groupe
Cannot connect to the Docker daemon Le démon ne tourne pas sudo systemctl status docker, puis sudo systemctl start docker
dial tcp: lookup registry-1.docker.io ... no such host La VM n'a pas accès à Internet ou au DNS ping -c 2 10.70.0.1, puis ping -c 2 9.9.9.9. Vérifier l'adresse et la passerelle dans le panneau Cloud-Init (étape 10)
toomanyrequests: You have reached your pull rate limit Docker Hub limite le nombre de téléchargements par adresse IP, et toute la classe sort par la même Prévenir l'enseignant
Des lignes comme [ 228.734113] docker0: port 1(veth5dfe819) entered blocking state s'intercalent dans les sorties La console xterm.js est la console série de la VM, où le noyau écrit aussi ses messages sudo dmesg -n 1, valable jusqu'au prochain redémarrage
Une commande longue se réécrit par-dessus elle-même sur la même ligne La console série annonce 80 colonnes, alors que la fenêtre est plus large stty cols 150 rows 40, à refaire à chaque connexion