Conseils Docker : débarrassez votre machine des fichiers indésirables

Conseils Docker : débarrassez votre machine des fichiers indésirables

Salut Habr ! Je présente à votre attention la traduction de l'article « Conseils Docker : nettoyez votre machine locale » l'auteur Luc Juggery.

Aujourd'hui, nous allons parler de la façon dont Docker utilise l'espace disque de la machine hôte, et nous verrons également comment libérer cet espace des restes d'images et de conteneurs inutilisés.


Conseils Docker : débarrassez votre machine des fichiers indésirables

Consommation totale

Docker est une bonne chose, probablement peu de gens en doutent aujourd'hui. Il y a quelques années à peine, ce produit nous a offert une toute nouvelle façon de créer, de fournir et d'exécuter n'importe quel environnement, nous permettant d'économiser considérablement les ressources CPU et RAM. En plus de cela (et pour certains ce sera le plus important) Docker nous a permis de simplifier et d'unifier incroyablement la gestion du cycle de vie de nos environnements de production.

Cependant, tous ces plaisirs de la vie moderne ont un prix. Lorsque nous exécutons des conteneurs, téléchargeons ou créons nos propres images et déployons des écosystèmes complexes, nous devons payer. Et nous payons, entre autres, avec de l'espace disque.

Si vous n'avez jamais pensé à l'espace réellement occupé par Docker sur votre machine, vous pourriez être désagréablement surpris par le résultat de cette commande :

$ docker system df

Conseils Docker : débarrassez votre machine des fichiers indésirables

Cela montre l'utilisation du disque de Docker dans différents contextes :

  • images – la taille totale des images téléchargées à partir de référentiels d'images et créées sur votre système ;
  • conteneurs – la quantité totale d'espace disque utilisée par les conteneurs en cours d'exécution (c'est-à-dire le volume total des couches de lecture-écriture de tous les conteneurs) ;
  • volumes locaux – le volume de stockage local monté sur des conteneurs ;
  • build cache – fichiers temporaires générés par le processus de création d’image (à l’aide de l’outil BuildKit, disponible à partir de Docker version 18.09).

Je parie qu'après ce simple transfert vous avez hâte de nettoyer votre disque des ordures et de redonner vie à de précieux gigaoctets (attention : surtout si vous payez un loyer pour ces gigaoctets chaque mois).

Utilisation du disque par conteneurs

Chaque fois que vous créez un conteneur sur la machine hôte, plusieurs fichiers et répertoires sont créés dans le répertoire /var/lib/docker, parmi lesquels il convient de noter les suivants :

  • Répertoire /var/lib/docker/containers/container_ID – lors de l'utilisation du pilote de journalisation standard, c'est ici que les journaux d'événements sont enregistrés au format JSON. Les journaux trop détaillés, ainsi que les journaux que personne ne lit ou ne traite autrement, entraînent souvent une saturation des disques.
  • Le répertoire /var/lib/docker/overlay2 contient les couches de lecture-écriture du conteneur (overlay2 est le pilote préféré dans la plupart des distributions Linux). Si le conteneur stocke les données dans son système de fichiers, alors c'est dans ce répertoire qu'il sera placé.

Imaginons un système sur lequel un Docker vierge est installé, qui n'a jamais été impliqué dans le lancement de conteneurs ou la création d'images. Son rapport d'utilisation de l'espace disque ressemblera à ceci :

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         0          0          0B         0B
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Lançons un conteneur, par exemple NGINX :

$ docker container run --name www -d -p 8000:80 nginx:1.16

Qu'arrive-t-il au disque :

  • les images occupent 126 Mo, c'est le même NGINX que nous avons lancé dans le conteneur ;
  • les conteneurs occupent 2 octets ridicules.

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          1          2B         0B (0%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

A en juger par la conclusion, nous n'avons pas encore d'espace à libérer. Puisque 2 octets sont complètement frivoles, imaginons que notre NGINX écrive de manière inattendue quelque part 100 mégaoctets de données et crée un fichier test.img exactement de cette taille en lui-même.

$ docker exec -ti www 
  dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*100]

Examinons à nouveau l'utilisation de l'espace disque sur l'hôte. Nous verrons que le ou les conteneurs y occupent 100 Mo.

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          1          104.9MB    0B (0%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Je pense que votre cerveau curieux se demande déjà où se trouve notre fichier test.img. Cherchons-le :

$ find /var/lib/docker -type f -name test.img
/var/lib/docker/overlay2/83f177...630078/merged/test.img
/var/lib/docker/overlay2/83f177...630078/diff/test.img

Sans entrer dans les détails, on peut noter que le fichier test.img est idéalement situé au niveau lecture-écriture, contrôlé par le pilote overlay2. Si nous arrêtons notre conteneur, l'hébergeur nous dira que cet espace peut, en principe, être libéré :

# Stopping the www container
$ docker stop www

# Visualizing the impact on the disk usage
$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          1          126M       0B (0%)
Containers     1          0          104.9MB    104.9MB (100%)
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Comment peut-on le faire? En supprimant le conteneur, ce qui impliquera de libérer l'espace correspondant au niveau lecture-écriture.

Avec la commande suivante, vous pouvez supprimer tous les conteneurs installés d'un seul coup et effacer votre disque de tous les fichiers en lecture-écriture créés par eux :

$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2

Total reclaimed space: 104.9MB

Nous avons donc libéré 104,9 Mo en supprimant le conteneur. Mais comme nous n'utilisons plus l'image précédemment téléchargée, elle devient également candidate à la suppression et à la libération de nos ressources :

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         1          0          126M       126M (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Remarque : Tant que l'image est utilisée par au moins un conteneur, vous ne pourrez pas utiliser cette astuce.

La sous-commande prune que nous avons utilisée ci-dessus n'a d'effet que sur les conteneurs arrêtés. Si nous voulons supprimer non seulement les conteneurs arrêtés mais également en cours d'exécution, nous devons utiliser l'une de ces commandes :

# Historical command
$ docker rm -f $(docker ps –aq)

# More recent command
$ docker container rm -f $(docker container ls -aq)

Notes complémentaires : si vous utilisez le paramètre -rm lors du démarrage d'un conteneur, alors lorsqu'il s'arrêtera, tout l'espace disque qu'il occupait sera libéré.

Utiliser des images disque

Il y a quelques années, une taille d'image de plusieurs centaines de mégaoctets était tout à fait normale : une image Ubuntu pesait 600 mégaoctets et une image Microsoft .Net pesait plusieurs gigaoctets. En ces temps difficiles, le téléchargement d’une seule image pouvait avoir un impact considérable sur votre espace disque libre, même si vous partagiez des niveaux entre les images. Aujourd'hui - louange aux grands - les images pèsent beaucoup moins, mais malgré cela, vous pouvez rapidement remplir les ressources disponibles si vous ne prenez pas quelques précautions.

Il existe plusieurs types d'images qui ne sont pas directement visibles par l'utilisateur final :

  • les images intermédiaires, sur la base desquelles d'autres images sont collectées - elles ne peuvent pas être supprimées si vous utilisez des conteneurs basés sur ces « autres » images ;
  • les images pendantes sont des images intermédiaires qui ne sont référencées par aucun des conteneurs en cours d'exécution - elles peuvent être supprimées.
  • Avec la commande suivante, vous pouvez vérifier les images pendantes sur votre système :

$ docker image ls -f dangling=true
REPOSITORY  TAG      IMAGE ID         CREATED             SIZE
none      none   21e658fe5351     12 minutes ago      71.3MB

Vous pouvez les supprimer de la manière suivante :

$ docker image rm $(docker image ls -f dangling=true -q)

Nous pouvons également utiliser la sous-commande prune :

$ docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Deleted Images:
deleted: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
deleted: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
deleted: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
deleted: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
deleted: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f

Total reclaimed space: 12.9kB

Si nous voulons soudainement supprimer toutes les images (et pas seulement les suspendre) avec une seule commande, alors nous pouvons faire ceci :

$ docker image rm $(docker image ls -q)

Utilisation du disque par volumes

Les volumes sont utilisés pour stocker des données en dehors du système de fichiers du conteneur. Par exemple, si nous voulons sauvegarder les résultats d’une application afin de les utiliser d’une autre manière. Un exemple courant est celui des bases de données.

Lançons un conteneur MongoDB, montons un volume externe au conteneur et restaurons une sauvegarde de base de données à partir de celui-ci (nous l'avons disponible dans le fichier bck.json) :

# Running a mongo container
$ docker run --name db -v $PWD:/tmp -p 27017:27017 -d mongo:4.0

# Importing an existing backup (from a huge bck.json file)
$ docker exec -ti db mongoimport 
  --db 'test' 
  --collection 'demo' 
  --file /tmp/bck.json 
  --jsonArray

Les données seront situées sur la machine hôte dans le répertoire /var/lib/docker/volumes. Mais pourquoi pas au niveau lecture-écriture du conteneur ? Car dans le Dockerfile de l'image MongoDB, le répertoire /data/db (où MongoDB stocke ses données par défaut) est défini comme un volume.

Conseils Docker : débarrassez votre machine des fichiers indésirables

Remarque : de nombreuses images qui doivent produire des données utilisent des volumes pour stocker ces données.

Lorsque nous jouons suffisamment avec MongoDB et arrêtons (ou peut-être même supprimons) le conteneur, le volume ne sera pas supprimé. Il continuera à occuper notre précieux espace disque jusqu'à ce que nous le supprimions explicitement avec une commande comme celle-ci :

$ docker volume rm $(docker volume ls -q)

Eh bien, ou nous pouvons utiliser la sous-commande prune qui nous est déjà familière :

$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da

Total reclaimed space: 25.82GB
luc@saturn:~$

Utilisation du disque pour le cache de création d'images

Dans Docker 18.09, le processus de création d'images a subi quelques modifications grâce à l'outil BuildKit. Cette chose augmente la vitesse du processus et optimise le stockage des données et la gestion de la sécurité. Ici, nous n'examinerons pas tous les détails de ce merveilleux outil ; nous nous concentrerons uniquement sur la manière dont il résout les problèmes d'utilisation de l'espace disque.

Disons que nous avons une application Node.Js complètement simple :

  • le fichier index.js démarre un simple serveur HTTP qui répond par une ligne à chaque requête reçue :
  • le fichier package.json définit les dépendances, dont seul expressjs est utilisé pour exécuter le serveur HTTP :

$ cat index.js
var express = require('express');
var util    = require('util');
var app = express();
app.get('/', function(req, res) {
  res.setHeader('Content-Type', 'text/plain');
  res.end(util.format("%s - %s", new Date(), 'Got Request'));
});
app.listen(process.env.PORT || 80);

$ cat package.json
    {
      "name": "testnode",
      "version": "0.0.1",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "dependencies": {
        "express": "^4.14.0"
      }
    }

Le Dockerfile pour créer l'image ressemble à ceci :

FROM node:13-alpine
COPY package.json /app/package.json
RUN cd /app && npm install
COPY . /app/
WORKDIR /app
EXPOSE 80
CMD ["npm", "start"]

Construisons l'image de la manière habituelle, sans utiliser BuildKit :

$ docker build -t app:1.0 .

Si nous vérifions l'utilisation de l'espace disque, nous pouvons voir que seules l'image de base (node:13-alpine) et l'image de destination (app:1.0) occupent de l'espace :

TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         2          0          109.3MB    109.3MB (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    0          0          0B         0B

Construisons la deuxième version de notre application, en utilisant BuildKit. Pour cela, il suffit de mettre la variable DOCKER_BUILDKIT à 1 :

$ DOCKER_BUILDKIT=1 docker build -t app:2.0 .

Si l'on vérifie maintenant l'utilisation du disque, nous verrons que le cache de build (buid-cache) y est désormais impliqué :

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMABLE
Images         2          0          109.3MB    109.3MB (100%)
Containers     0          0          0B         0B
Local Volumes  0          0          0B         0B
Build Cache    11         0          8.949kB    8.949kB

Pour l'effacer, utilisez la commande suivante :

$ docker builder prune
WARNING! This will remove all dangling build cache.
Are you sure you want to continue? [y/N] y
Deleted build cache objects:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi

Total reclaimed space: 8.949kB

Tout effacer!

Nous avons donc envisagé de nettoyer l'espace disque occupé par les conteneurs, les images et les volumes. La sous-commande prune nous y aide. Mais il peut également être utilisé au niveau du système Docker, et il nettoiera tout ce qu'il peut :

$ docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N]

Si, pour une raison quelconque, vous économisez de l'espace disque sur votre machine Docker, l'exécution périodique de cette commande devrait devenir une habitude.

Source: habr.com

Ajouter un commentaire