virli/tutorial/1/first.md
2017-11-22 03:35:40 +01:00

6.8 KiB

\newpage

Mon premier conteneur

Afin de tester la bonne marche de votre installation, exécutons la commande :

docker run hello-world

Cette commande va automatiquement exécuter une série de commandes pour nous, comme indiqué dans le message affiché en retour :

D'abord, le daemon va rechercher s'il possède localement l'image hello-world. Si ce n'est pas le cas, il va aller la récupérer sur hub.docker.com. Ce site met à disposition un grand nombre d'images : des systèmes de base comme Ubuntu, Debian, Centos, etc. jusqu'à des conteneurs prêts à l'emploi : le serveur web nginx, la base de données MySQL, un serveur node.js, etc.

Nous pouvons directement utiliser le client pour rechercher une image sur le hub, en utilisant la commande search :

docker search mariadb

Il est possible de mettre à jour les images locales ou simplement pré-télécharger des images depuis le hub en utilisant la commande pull :

docker pull ubuntu

Pour consulter la liste des images dont nous disposons localement (soit parce qu'on les a téléchargées, soit parce que nous les avons créées nous-même), on utilise la commande images :

docker images

Vous devriez constater la présence de plusieurs images « Ubuntu », mais chacune a un TAG différent. En effet, souven, il existe plusieurs versions d'une même image. Pour Ubuntu par exemple, nous avons la possibilité de lancer la version precise, trusty, xenial ou yakkety.

Chaque image est identifiable par son Image ID unique ; les noms d'images ainsi que leurs tags sont, comme les tags Git, une manière humainement plus simple de faire référence aux identifiants.

Chaque nom d'image possède au moins un tag associé : latest. C'est le tag qui est automatiquement recherché lorsque l'on ne le précisez pas en lançant l'image.

Exécuter un programme dans un conteneur

Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu, lançons-la !

La commande run de Docker prend comme derniers arguments le programme à lancer dans le conteneur ainsi que ses éventuels arguments. Essayons d'afficher un Hello World :

docker run ubuntu /bin/echo "Hello World"

Dans notre exemple, c'est bien le /bin/echo présent dans le conteneur qui est appelé. Ce n'est pas le programme /bin/echo de la machine hôte qui a été transféré dans le conteneur.

Pour nous en convaincre, nous pouvons tenter d'exécuter un programme qui n'est pas présent sur notre machine, mais bien uniquement dans le conteneur. Si vous n'utilisez pas Alpine Linux, vous pourriez tenter d'utiliser son gestionnaire de paquet apk, via :

docker run alpine /sbin/apk stats

Modifier une image

Images vs. conteneurs

À chaque fois que nous lançons un run, un nouveau conteneur est créé. L'image fournie comme argument est utilisée comme un modèle de base pour le conteneur et est recopiée grâce à un mécanisme de Copy-On-Write : c'est donc très rapide et ne consomme pas beaucoup d'espace disque.

Étant donné que chaque conteneur est créé à partir d'un modèle, cela signifie que lorsque nous exécutons une commande modifiant les fichiers d'un conteneur, cela ne modifie pas l'image de base, mais crée une nouvelle image. Que nous pouvons ensuite utiliser comme image de base.

Images vs. conteneurs

Dans ce schéma, on considère les images comme étant la partie figée de Docker à partir desquelles on peut créer des conteneurs.

Si l'on souhaite qu'une modification faite dans un conteneur (par exemple l'installation d'un paquet) s'applique à d'autres conteneurs, il va falloir créer une nouvelle image à partir de ce conteneur.

Les paramètres

Pour créer une image, commençons par entrer dans un nouveau conteneur :

docker run -it ubuntu /bin/bash

Vous avez remarqué l'utilisation des options --tty et --interactive ? Avant le nom de l'image, elles sont gérées par Docker pour modifier le comportement du run. En fait, tout comme git(1) et ses sous-commandes, chaque niveau de commande peut prendre des paramètres :

docker DOCKER_PARAMS run RUN_OPTS image IMAGE_CMD IMAGE_ARGS ...

Par exemple :

docker -H unix:///var/run/docker.sock run -it alpine /bin/ash -c "echo foo"

Ici, l'option -H sera traitée par le client Docker (pour définir l'emplacement du point de communication avec le daemon), tandis que les options -it seront utilisées lors du traitement du run. Quant au -c, il sera simplement tranmis au conteneur comme argument au premier execve(2) du conteneur.

Avec l'option --interactive, on s'assure que l'entrée standard ne sera pas fermée (close(2))1. Nous demandons également l'allocation d'un TTY, sans quoi bash ne se lancera pas en mode interractif2.

Modification interractive

Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de superflu : il n'y a même pas d'éditeur de texte : ni vim, ni emacs, même pas vi !

La première chose à faire est de télécharger la liste des paquets. En effet, afin de ne pas livrer de superflu, la liste des paquets et son cache ne sont pas inclues dans le conteneur.

apt-get update

Il peut arriver que des paquets présents dans l'image ne soient pas à jour. Afin de garder un environnement cohérent, il est recommandé de ne pas utiliser le gestionnaire de paquets pour mettre à jour les paquets présent de base, mais plutôt de contacter le mainteneur de l'image pour qu'il la mette à jour.

Installons maintenant un programme :

apt-get install nano

En attendant la fin de l'installation, jetons un œil à la commande dans un autre terminal :

docker ps

Cette commande liste les conteneurs actifs. Notez le Container ID ainsi que le NAMES du conteneur du conteneur actuellement en cours d'installation de nano.

Lorsque l'installation de nano est terminée, quittez l'image en tapant exit.

Sauvegardez votre image modifiée avec la commande commit pour pouvoir commencer directement de votre image avec nano :

docker commit CONTAINER my_nano

En remplaçant CONTAINER par le nom ou l'identifiant de votre container. my_nano est le nom que vous voudrez utiliser à la place d'ubuntu :

docker run -it my_nano /bin/bash

Vous constatez cette fois que vous pouvez lancer nano, alors que vous ne pouvez toujours pas le faire dans un conteneur issue d'une image ubuntu !


  1. TODO ↩︎

  2. Mais il sera possible de l'utiliser sans allouer de TTY, comme par exemple en faisant :

    42sh$ cat cmd
    echo foo
    42sh$ cat cmd | docker run -i busybox
    foo
    

    L'option -i reste néanmoins nécessaire pour que l'entrée standard soit transmise au conteneur. ↩︎