On va parler ici de stockage des images docker, ou sont elles stockées ? Sous quelle forme ?...
Il est également important pour nous de comprendre la stratégie de copie en écriture (Copy on Write: CoW).
Copy on write est un mécanisme d'optimisation utilisé par Docker (et d'autres technologies de conteneur) en relation avec les systèmes de fichiers, en particulier lors de la création et de la manipulation de conteneurs et d'images. Le principe de base de CoW est assez simple : au lieu de copier immédiatement des données lorsqu'une opération le demande, les données sont copiées uniquement lorsque l'une d'elles est modifiée.
Exemple :
Lorsque vous téléchargez une image, comme celle de ubuntu
, cette image est composée de plusieurs couches. Si vous téléchargez ensuite une autre image, comme celle de nginx
, qui est également basée sur ubuntu
, Docker ne téléchargera pas à nouveau toutes les couches communes à ubuntu
. Au lieu de cela, les couches déjà présentes sur votre système seront copiés (CoW) pour l'image nginx
.
Il existe plusieurs pilotes de stockage disponibles dans Docker, notamment :
Pour voir le type de driver :
$ docker info
...
Server:
...
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Le répertoire /var/lib/docker/overlay2/
est utilisé pour stocker les couches des images Docker ainsi que les couches de lecture-écriture des conteneurs :
$ docker service create nginx
bfiwhtpllcgsk93j8s81df2u2
...
$ ls -al
total 52
drwx--x--- 13 root root 4096 Oct 7 19:40 .
drwx--x--- 13 root root 4096 Oct 7 19:34 ..
drwx--x--- 5 root root 4096 Oct 7 19:40 21f4fe9a70d604c609d2f75b901196c0b93b7f9368d752630c9593159e25d400
drwx--x--- 4 root root 4096 Oct 7 19:40 21f4fe9a70d604c609d2f75b901196c0b93b7f9368d752630c9593159e25d400-init
drwx--x--- 4 root root 4096 Oct 7 19:40 468e19ff891e72158007a26959298fe6a7dc9d149381f786ef55b8b5da68e6f6
drwx--x--- 3 root root 4096 Oct 7 19:40 533c4e14c203efc1260c6211f882f35e38c1e21b745b65893a8c4747e7be0ce5
drwx--x--- 4 root root 4096 Oct 7 19:40 77fa08b7f6318d2a79e1044200ecc9cf6d0acb979b3a383c3ef6ec37bc9b7333
drwx--x--- 4 root root 4096 Oct 7 19:40 7de267cf9791c2a2cf54b7d586125c36ba3c20c8dd3e6828ba9da7164ba912d9
drwx--x--- 4 root root 4096 Oct 7 19:40 bda0a237fd54dcfd46a585c0c653b7bbc785e7fb4399580d609fa245deb8a218
drwx--x--- 3 root root 4096 Oct 7 19:34 e0a7b0c05e190b8fb8ab5398834df52a9e65a55b3634e80788786f773163170f
drwx--x--- 4 root root 4096 Oct 7 19:40 f36966b0934aaca66296219269af2de06cdfbc7d99c68982fe918628f75a1df5
drwx--x--- 4 root root 4096 Oct 7 19:40 fb374bc7bd30e9ee577336d0d125c8964fbc05be9c0e55c928b10f3475a2479a
drwx------ 2 root root 4096 Oct 7 19:40 l
Chaque dossier correspond à un layer. Si on va dans un d’entre eux :
$ cd 2121f4fe9a70d604c609d2f75b901196c0b93b7f9368d752630c9593159e25d400
...
$ ls -al
total 28
drwx--x--- 5 root root 4096 Oct 7 19:40 .
drwx--x--- 13 root root 4096 Oct 7 19:40 ..
drwxr-xr-x 6 root root 4096 Oct 7 19:40 diff
-rw-r--r-- 1 root root 26 Oct 7 19:40 link
-rw-rw-rw- 1 root root 231 Oct 7 19:40 lower
drwxr-xr-x 1 root root 4096 Oct 7 19:40 merged
drwx------ 3 root root 4096 Oct 7 19:40 work
diff/
: Contient les fichiers qui ont été ajoutés ou modifiés dans cette couche par rapport à la couche précédente.link
: Un fichier qui contient un identifiant unique pour la couche.lower
: Un fichier qui liste les couches inférieures sur lesquelles cette couche est superposée.merged/
: Un point de montage où le système de fichiers complet (toutes les couches superposées) est accessible.work/
: Un répertoire utilisé par OverlayFS pour gérer les opérations de Copy-on-Write.$ cat link
C574D66OIMUCZL5PMIN25XDNRT
$ cat lower
l/QGVSUSC23VOD5Q2JF32UBGCFIW:l/M7GZJSEZ7MACREFMEDMJ6YMMKI:l/VDRCQMT4XKA2FQPA3IOQVXZNJE:l/64LQVYUK3INPSKURCN5DFGDR6Y:l/A5IXRTQAKJ3RWUH4AYFHSGKIB2:l/CPSNWXH6TO6APJKMW6CBJLWZG6:l/3ULVCMMPCJRUTNYDMEJQ4F4TVO:l/3E2PWEKCSET4Y35PMIIVT2QULF
Si on retourne dans overlay2/
on peut voir un dossier l/
. Ce répertoire l/
contient des liens symboliques vers les répertoires diff/
des couches. Ces liens sont utilisés pour accéder rapidement aux données des couches :
$ cd l/
$ ls -al
total 48
drwx------ 2 root root 4096 Oct 7 19:40 .
drwx--x--- 13 root root 4096 Oct 7 19:40 ..
lrwxrwxrwx 1 root root 72 Oct 7 19:40 3E2PWEKCSET4Y35PMIIVT2QULF -> ../533c4e14c203efc1260c6211f882f35e38c1e21b745b65893a8c4747e7be0ce5/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 3ULVCMMPCJRUTNYDMEJQ4F4TVO -> ../bda0a237fd54dcfd46a585c0c653b7bbc785e7fb4399580d609fa245deb8a218/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 64LQVYUK3INPSKURCN5DFGDR6Y -> ../468e19ff891e72158007a26959298fe6a7dc9d149381f786ef55b8b5da68e6f6/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 A5IXRTQAKJ3RWUH4AYFHSGKIB2 -> ../f36966b0934aaca66296219269af2de06cdfbc7d99c68982fe918628f75a1df5/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 C574D66OIMUCZL5PMIN25XDNRT -> ../21f4fe9a70d604c609d2f75b901196c0b93b7f9368d752630c9593159e25d400/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 CPSNWXH6TO6APJKMW6CBJLWZG6 -> ../77fa08b7f6318d2a79e1044200ecc9cf6d0acb979b3a383c3ef6ec37bc9b7333/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 M7GZJSEZ7MACREFMEDMJ6YMMKI -> ../7de267cf9791c2a2cf54b7d586125c36ba3c20c8dd3e6828ba9da7164ba912d9/diff
lrwxrwxrwx 1 root root 77 Oct 7 19:40 QGVSUSC23VOD5Q2JF32UBGCFIW -> ../21f4fe9a70d604c609d2f75b901196c0b93b7f9368d752630c9593159e25d400-init/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:34 RB4CWKO2BDCUTE62GZ5H5PPI36 -> ../e0a7b0c05e190b8fb8ab5398834df52a9e65a55b3634e80788786f773163170f/diff
lrwxrwxrwx 1 root root 72 Oct 7 19:40 VDRCQMT4XKA2FQPA3IOQVXZNJE -> ../fb374bc7bd30e9ee577336d0d125c8964fbc05be9c0e55c928b10f3475a2479a/diff
On a ici tous les liens symboliques vers les layers.
Voici quel type de stockage propose Docker selon la distribution :
(source : Docker)
Le changement de driver rend les containers créés auparavant inaccessibles. De même pour les datas.
Pour changer de driver :
$ systemctl stop docker
$ cd /etc/docker
$ vim daemon.json
{
"storage-driver": "aufs"
}
$ systemctl start docker
$ docker info
...
Storage Driver: aufs
Par défaut, tous les fichiers créés à l'intérieur d'un conteneur sont stockés sur une couche conteneur inscriptible.
Cela signifie que :
Docker propose aux conteneurs deux options pour stocker les fichiers sur la machine hôte, de sorte que les fichiers soient conservés même après l'arrêt du conteneur : les volumes et les montages bind.
Si vous exécutez Docker sous Linux, vous pouvez également utiliser un montage tmpfs (en mémoire).
Un volume donné peut être monté dans plusieurs conteneurs simultanément.
Lorsqu'aucun conteneur en cours d'exécution n'utilise un volume, celui-ci est toujours disponible pour Docker et n'est pas supprimé automatiquement.
Lorsque vous montez un volume, il peut être nommé ou anonyme. Les volumes anonymes ne reçoivent pas de nom explicite lorsqu'ils sont montés pour la première fois dans un conteneur. Docker leur donne donc un nom aléatoire qui est garanti comme étant unique au sein d'un hôte Docker donné.
Lister les volumes :
docker volume ls
Création d’un volume (de type volume) :
docker volume create myvolume
Comme tous les objets docker, nous pouvons inspecter les volumes docker :
$ docker volume inspect myvolume
[
{
"CreatedAt": "2023-08-24T15:57:21Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/myvolume/_data",
"Name": "myvolume",
"Options": null,
"Scope": "local"
}
]
On peut maintenant associer un container à ce volume :
docker container run -d --name busybox -v <SOURCE>:<DEST> <IMAGE>
# Soit :
docker container run -d --name busybox -v myvolume:/etc busybox sh
Tout ce qui sera dans /etc du container busybox sera donc sauvegardé dans /var/lib/docker/volumes/myvolume
:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
cela va créer le volume sans nom qui partage “myvol/”. Cela n’est cependant pas recommandé car cela va créer un volume avec un nom random.
On peut aussi nettoyer les volumes grâce à la commande prune :
# Efface tous les volumes "anonymes" qui ne sont plus utilisés (crée par docker avec un nom aléatoire)
docker volume prune
# Efface tous les volumes non utilisés
docker volume prune -a
Lorsqu’on utilise un bind mount, un fichier ou un répertoire sur la machine hôte est monté dans un conteneur.
--mount
syntaxe :
-v
syntaxe (non utilisable pour les services) :
Soit :
docker run -v /home/antoine:/root:ro busybox
Tout changement de fichier/dossier dans le dossier /home/antoine sur la machine hote ou le container sera répercuté aux 2 endroits (hote + container)
Le fichier ou le répertoire est référencé par son chemin complet ou relatif sur la machine hôte.
$ cd /root
$ mkdir index/
$ echo "Hello toto" > index/index.html
# Via le paramètre -v :
$ docker container run -dt --name mynginx -v /root/index:/usr/share/nginx/html nginx
# Via --mount
$ docker container run -dt --name mynginx --mount type=bind,source=/root/index,target=/usr/share/nginx/html nginx
Si jamais on ne veut pas que le fichier soit modifié par le container :
type=bind,source=/root/index,target=/usr/share/nginx/html,readonly
Lorsqu'un conteneur est créé avec l'option -dt et que le processus principal est terminé/arrêté, il passe à l'étape Exited.
Nous pouvons voir la liste de tous les conteneurs (Running/Exited) avec la commande
docker ps -a
Souvent, les conteneurs effectuent un travail et nous voulons que le conteneur soit automatiquement supprimé lorsqu'il quitte. Ceci peut être réalisé avec l'option --rm.
docker container run --rm -it --name container02 -v /testvolume busybox ping -c10 google.com
Le volume sera supprimé une fois que les 10 pings seront finis. Dans ce cas, le volume n'a aucun intérêt, mais c'était pour l'exemple.
Le device mapper est un driver fourni par le noyau Linux pour mapper les périphériques de bloc physiques sur des périphériques de bloc virtuels de niveau supérieur.
Le device mapper fonctionne en faisant passer des données d'un périphérique de bloc virtuel, qui est fourni par le mappeur de périphériques lui-même, à un autre périphérique de bloc.
Le device mapper crée des périphériques logiques au-dessus d'un périphérique de bloc physique et fournit des fonctionnalités telles que :
Il existe deux modes pour le pilote de stockage devicemapper :
Pour le mettre en place :
$ systemctl stop docker
$ cd /etc/docker
$ vim daemon.json
{
"storage-driver": "devicemapper"
}
$ systemctl start docker
$ docker info | grep storage
...
Storage Driver: devicemapper
Normalement, ce storage driver n'est plus recommandé. overlay2
est devenu la norme, mais pour le DCA, il faut connaitre son existence.
Les commandes UNIX et Linux ouvrent généralement trois flux d'I/O lors de leur exécution, appelés STDIN, STDOUT et STDERR.
Il existe de nombreuses options de journalisation disponibles dans Docker, dont les suivantes :
La commande docker logs n'est pas disponible pour les pilotes autres que json-file et journald.
Pour voir le STDOUT d’un container :
docker logs mywebserver
Pour trouver le driver logging d’un container :
$ docker container inspect busybox -f "{{ json .HostConfig.LogConfig.Type }}"
"json-file"
Pour trouver le fichier de log du container :
$ docker container inspect busybox -f "{{ json .LogPath }}"
"/var/lib/docker/containers/2e81738745a03b6d95eaad716b1858488efa1f091e0d39388f5861596ad2c945/2e81738745a03b6d95eaad716b1858488efa1f091e0d39388f5861596ad2c945-json.log"
Pour forcer un driver particulier :
docker container run -d --name mycustomlog --log-driver none busybox ping google.com
Si on essaie de regarder les logs de ce container sans "log driver" :
$ docker logs mycustomlog
Error response from daemon: configured logging driver does not support reading