Quand un journal grossit sans fin ou qu'une écriture échoue, la tentation est
de supprimer au hasard, et vous risquez d'effacer une donnée encore utile. Cette
leçon vous montre comment borner les journaux d'un conteneur, vérifier que
la limite s'applique vraiment, lire l'occupation du disque par catégorie et
libérer un fichier jetable sans recréer le conteneur. Les mesures viennent d'une
VM Debian 13 avec Docker Engine 29.9.2 et Compose 5.6.1. Les gestes qui
modifient le démon système, comme changer daemon.json, ont été mesurés sur une
VM jetable : ne les rejouez pas sur un hôte partagé.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Chaque geste se vérifie sur l'état réel du moteur, pas seulement dans un fichier de configuration.
- Vous lisez le pilote actif, les options du conteneur et le chemin de son journal.
- Vous vérifiez que les fichiers tournent après une écriture qui dépasse leur taille maximale.
- Vous distinguez une option propre au conteneur d'une valeur par défaut du démon.
- Vous mesurez les images, les conteneurs, les volumes et le cache, puis vous
comparez ce que
docker system dfannonce à l'espace réellement rendu, avant de choisir ce qui peut être supprimé. - Vous repérez un manque d'octets ou d'inodes (les entrées qui permettent de créer des fichiers) et libérez l'espace sans remplacer le conteneur.
Prérequis
Section intitulée « Prérequis »Vous devez savoir lancer un conteneur et lire sa configuration. La leçon
Configurer le daemon Docker (daemon.json)
explique le rôle de daemon.json, les options du démon et son redémarrage.
Les sorties ci-dessous ont été relevées le 4 novembre 2026 sur la VM de référence. L'image de démonstration est épinglée à son digest :
IMAGE="alpine:3.23@sha256:ff7f0c727dd796aa36787bfcd9a64bf35a6ce72a73451b3359fde849b6703d63"mkdir -p ~/journaux-disque/composecd ~/journaux-disquepwd/home/ansible/journaux-disqueJouez les blocs de cette leçon dans l'ordre et dans un même terminal. Ils
réutilisent les variables IMAGE, R et SPACE_ID, le répertoire courant et,
pendant la mesure du cache, DOCKER_HOST. Dans un autre terminal, ces
variables n'existent pas : redéfinissez-les avant de continuer.
Le dossier ~/journaux-disque contient uniquement les fichiers créés pour cette
démonstration. Les exemples n'exposent aucun port et utilisent des noms
différents de ceux des deux labs.
Quel pilote écrit les journaux, et où ?
Section intitulée « Quel pilote écrit les journaux, et où ? »Le pilote de journalisation décide comment Docker conserve les sorties
standard et d'erreur d'un conteneur. Sur cette VM, le pilote par défaut était
json-file, qui écrit un fichier JSON par conteneur (voir la
configuration et le
pilote json-file).
Ce pilote ne borne pas les journaux par défaut : le test suivant a produit
un fichier de 172 298 octets sans aucune option de rotation.
docker info --format '{{.LoggingDriver}}'
docker run -d --name c35b-log-open --network none "$IMAGE" \ sh -c 'i=0; while [ "$i" -lt 160 ]; do printf "%05d:" "$i"; printf "%01000d\n" 0; i=$((i+1)); done'printf 'open_exit='docker wait c35b-log-opendocker inspect c35b-log-open \ --format 'type={{.HostConfig.LogConfig.Type}} options={{json .HostConfig.LogConfig.Config}} path={{.LogPath}}'OPEN_LOG=$(docker inspect c35b-log-open --format '{{.LogPath}}')printf 'open_log_size='sudo stat -c '%s' "$OPEN_LOG"printf 'open_log_files='sudo find "$(dirname "$OPEN_LOG")" -maxdepth 1 -type f -name "$(basename "$OPEN_LOG")*" | wc -ljson-fileopen_exit=0type=json-file options={} path=/var/lib/docker/containers/f4a0128ad251dc71241206adfe3126b3206c5ab9f7dd55ac3710a6d6d9f1716f/f4a0128ad251dc71241206adfe3126b3206c5ab9f7dd55ac3710a6d6d9f1716f-json.logopen_log_size=172298open_log_files=1Dans la sortie, regardez deux choses. options={} dit qu'aucune limite n'est
configurée, et path= donne l'emplacement du journal, dans un dossier nommé
d'après l'identifiant du conteneur. docker inspect les lit dans
HostConfig.LogConfig et LogPath. Le fichier appartient à root : la mesure
a lu sa taille avec sudo, sans changer ses permissions.
Le pilote local est une alternative à json-file. La documentation du
pilote local
décrit son stockage interne et sa rotation. Le test plus bas vérifie seulement
que docker logs lit ses journaux, sans mesurer ses limites par défaut.
Comment vérifier qu'une rotation est effective ?
Section intitulée « Comment vérifier qu'une rotation est effective ? »Trois options règlent la rotation : max-size fixe la taille maximale d'un
fichier, max-file le nombre de fichiers conservés et compress compresse les
fichiers déjà tournés. Vous les posez sur le conteneur, sans toucher au
pilote par défaut du démon. Elles se fixent à la création : docker run
ou docker create les reçoit, et un conteneur existant ne les change pas. Pour
modifier une limite, vous recréez le conteneur.
docker run -d --name c35b-log-capped --network none \ --log-driver=json-file --log-opt max-size=36k --log-opt max-file=4 \ --log-opt compress=true \ "$IMAGE" sh -c 'i=0; while [ "$i" -lt 160 ]; do printf "%05d:" "$i"; printf "%01000d\n" 0; i=$((i+1)); done'printf 'capped_exit='docker wait c35b-log-cappeddocker inspect c35b-log-capped \ --format 'type={{.HostConfig.LogConfig.Type}} options={{json .HostConfig.LogConfig.Config}}'CAPPED_LOG=$(docker inspect c35b-log-capped --format '{{.LogPath}}')printf 'capped_log_files=%s\n' "$(sudo find "$(dirname "$CAPPED_LOG")" -maxdepth 1 -type f -name "$(basename "$CAPPED_LOG")*" | wc -l)"capped_exit=0type=json-file options={"compress":"true","max-file":"4","max-size":"36k"}capped_log_files=4Le test a compté quatre fichiers sur l'hôte : le journal courant et trois
fichiers tournés compressés. Les options affichées par inspect ne prouvent
pas que la rotation a eu lieu, elles disent seulement ce qui a été demandé.
Il faut dépasser le plafond, puis compter les fichiers dans le dossier indiqué
par LogPath.
Sans privilège, docker logs donne aussi la preuve. docker logs c35b-log-capped | wc -l
a rendu 126 lignes sur les 160 écrites, et la première ligne relue commençait
par 00034. Les 34 premières lignes ont disparu avec le fichier le plus ancien :
la limite s'applique, et ce qui dépasse le nombre de fichiers est perdu.
Compose accepte les mêmes options sous logging.options, et leurs valeurs sont
des chaînes dans le fichier YAML. Enregistrez le service suivant dans
~/journaux-disque/compose/compose.yaml. Il pose un plafond différent de celui
de la commande précédente. docker compose config -q le valide, puis up -d
l'exécute.
services: journal-writer: image: ${IMAGE} command: - sh - -c - 'i=0; while [ "$$i" -lt 96 ]; do printf "%05d:" "$$i"; printf "%01000d\n" 0; i=$$((i+1)); done' logging: driver: json-file options: max-size: "24k" max-file: "4" compress: "true"IMAGE="$IMAGE" docker compose -p c35b-log-compose -f compose/compose.yaml config -qIMAGE="$IMAGE" docker compose -p c35b-log-compose -f compose/compose.yaml up -dIMAGE="$IMAGE" docker compose -p c35b-log-compose -f compose/compose.yaml wait journal-writerCOMPOSE_CID=$(IMAGE="$IMAGE" docker compose -p c35b-log-compose -f compose/compose.yaml ps -aq journal-writer)COMPOSE_LOG=$(docker inspect "$COMPOSE_CID" --format '{{.LogPath}}')printf 'compose_log_files=%s\n' "$(sudo find "$(dirname "$COMPOSE_LOG")" -maxdepth 1 -type f -name "$(basename "$COMPOSE_LOG")*" | wc -l)"compose_log_files=4Quatre fichiers sont donc présents aussi avec Compose. Le pilote par défaut du
démon est resté json-file après ces deux configurations, puisqu'elles ne
touchent que leur conteneur. La
documentation liste les
autres options disponibles.
Avec le pilote local, le test vérifie que docker logs rend les sorties et
qu'inspect renvoie un LogPath vide : il n'y a pas de fichier JSON à compter.
docker run -d --name c35b-log-local --network none --log-driver=local \ "$IMAGE" sh -c 'printf "local-driver-check\n"'printf 'local_exit='docker wait c35b-log-localdocker inspect c35b-log-local \ --format 'type={{.HostConfig.LogConfig.Type}} options={{json .HostConfig.LogConfig.Config}} path={{.LogPath}}'docker logs --tail 1 c35b-log-localprintf 'daemon_default_after_per_container_tests='docker info --format '{{.LoggingDriver}}'local_exit=0type=local options={} path=local-driver-checkdaemon_default_after_per_container_tests=json-fileQuand les valeurs de daemon.json s'appliquent-elles ?
Section intitulée « Quand les valeurs de daemon.json s'appliquent-elles ? »Les valeurs de log-opts dans daemon.json deviennent les valeurs par défaut
des nouveaux conteneurs, après le redémarrage du démon. Docker attend des
chaînes, y compris pour les tailles, les nombres de fichiers et les booléens.
Voici la configuration testée :
{ "log-driver": "json-file", "log-opts": { "max-size": "48k", "max-file": "3", "compress": "true" }}Dans le schéma, regardez la branche de gauche : le redémarrage du démon ne modifie pas un conteneur déjà créé. Seul un conteneur créé après lui, ou recréé, reçoit les nouvelles valeurs.
Le test a donné trois résultats :
- Le conteneur créé avant le changement a gardé
options={}après le redémarrage. Relancé sans être recréé, il a écrit environ 344 600 octets dans un seul fichier, soit deux exécutions de 172 300 octets. - Un nouveau conteneur a reçu les trois options et produit trois fichiers, dont un journal courant de 26 923 octets.
- L'ancien conteneur, supprimé puis recréé, a reçu un nouvel identifiant et les nouvelles valeurs par défaut.
Pour qu'un conteneur existant hérite des nouvelles valeurs, il faut donc le
recréer : le redémarrer ne suffit pas. Le test a modifié daemon.json,
redémarré le démon, puis remis la configuration d'origine. Sur un hôte réel,
relisez d'abord la configuration existante et la procédure de redémarrage
décrites dans
Configurer le daemon Docker (daemon.json).
Que faut-il mesurer avant de reprendre de l'espace ?
Section intitulée « Que faut-il mesurer avant de reprendre de l'espace ? »docker system df répartit l'occupation du disque par Docker entre
quatre catégories : images, conteneurs, volumes et cache de construction.
docker system df -v détaille ensuite les éléments de chaque catégorie. Le
tableau résume ce que chaque ligne regroupe.
| Ligne | Ressource mesurée |
|---|---|
Images | Images locales, tailles partagées et uniques dans la vue détaillée. |
Containers | Espace associé aux conteneurs, y compris ceux qui sont arrêtés. |
Local Volumes | Volumes locaux et espace occupé. |
Build Cache | Cache de construction des images. |
La colonne RECLAIMABLE décrit un potentiel de récupération, pas une
autorisation de supprimer sans avoir examiné le périmètre. La documentation de
docker system df
décrit les vues résumé et détaillée.
Pour mesurer sans toucher au démon système, lancez un démon secondaire isolé.
Il a son propre socket, son propre --data-root et son propre espace de noms
containerd (--containerd-namespace et --containerd-plugins-namespace). Sans
ces deux dernières options, il partagerait avec le démon système le magasin
d'images containerd et afficherait ses images dans docker image ls. Vous
construisez ensuite une image qui laisse du cache, sans réseau puisque ce démon
n'a pas de pont.
Deux précautions encadrent le lancement. sudo -v demande votre mot de passe
avant que dockerd parte en arrière-plan : sans lui, sudo pourrait attendre
une saisie que vous ne voyez pas. Ensuite, la boucle attend le socket pendant
30 secondes au plus, puis le script affiche un message qui renvoie au journal
dockerd.log si le démon n'a pas démarré.
R=/tmp/c35b-secmkdir -p "$R/ctx"printf 'FROM %s\nRUN dd if=/dev/urandom of=/blob1 bs=1M count=8\nRUN dd if=/dev/urandom of=/blob2 bs=1M count=8\n' "$IMAGE" > "$R/ctx/Dockerfile"sudo -vsudo dockerd --host "unix://$R/d.sock" --data-root "$R/data" --exec-root "$R/exec" \ --pidfile "$R/d.pid" --bridge none --iptables=false --ip-masq=false \ --containerd-namespace c35b-ns --containerd-plugins-namespace c35b-plug \ > "$R/dockerd.log" 2>&1 &export DOCKER_HOST="unix://$R/d.sock"for i in $(seq 1 30); do [ -S "$R/d.sock" ] && break; sleep 1; done[ -S "$R/d.sock" ] || echo "dockerd n'a pas démarré, lisez $R/dockerd.log"sleep 3sudo -E docker pull -q "$IMAGE"sudo -E docker build --network none -q -t c35b-cache-img "$R/ctx"sleep 3sudo -E docker system dfsudo -E docker system df -vsudo -E docker builder prune --all --filter until=1s --forcesudo -E docker system dfLes lignes utiles de la mesure, avant puis après la suppression :
Build Cache 5 0 46.52MB 12.29kBTotal: 46.52MBBuild Cache 0 0 0B 0BRegardez la colonne RECLAIMABLE. Avant la suppression, elle affichait
12,29 kB, alors que docker builder prune --all a affiché Total: 46.52MB.
Aucun de ces deux chiffres ne mesure l'espace rendu au disque : le Total
additionne les entrées de cache retirées, et RECLAIMABLE laisse de côté tout
ce qui est partagé. docker system df -v montre ce partage avec sa colonne
SHARED :
CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHAREDnyf6pjznkc80 source.local 8.19kB 4 seconds ago 3 seconds ago 1 falsew4p1wknca9ib source.local 4.1kB 4 seconds ago 3 seconds ago 1 falsek8ydgs149k1x regular 12.9MB 4 seconds ago 3 seconds ago 1 true1ml2p8gkqeaj regular 16.8MB 3 seconds ago 3 seconds ago 1 trueccvs2ctqyta1 regular 16.8MB 3 seconds ago 3 seconds ago 1 trueAvec le magasin containerd, les trois couches regular sont partagées avec
l'image alpine et avec l'image construite. Tant que cette image existe,
RECLAIMABLE ne compte pas ce qui est partagé : il vaut 12,29 kB, la somme des
deux entrées source.local. Partagé ne veut pourtant pas dire conservé. Mesuré
sur la VM jetable avec df -B1 --output=used /var/lib/containerd, le prune a
rendu environ 26 MB : RECLAIMABLE sous-estimait l'espace rendu, et le
Total le surestimait.
Un second ordre de mesure donne le même sens d'écart. Quand l'image est
supprimée avant le prune, les deux couches de 16,8 MB passent à SHARED false et
RECLAIMABLE affiche 33.59MB. Le prune a pourtant rendu environ 43 MB : là
encore, RECLAIMABLE annonçait moins que l'espace réellement rendu.
Seul df tranche, parce qu'il mesure le disque et non une estimation du
moteur. Ces mesures valent pour ce démon et cette image. Retenez la méthode
plutôt que les chiffres : relevez df avant et après, et ne prenez ni
RECLAIMABLE ni le Total de prune pour l'espace que vous allez récupérer.
Le sleep 3 avant la mesure compte. Lancé juste après la construction, le
filtre until=1s n'a rien supprimé (Total: 0B), parce que le cache avait
servi moins d'une seconde plus tôt. Cette valeur ne servait qu'à rendre le cache
éligible pendant l'essai : ne la copiez pas sur un hôte partagé. Choisissez un
seuil selon vos besoins, après avoir lu docker system df -v. La
documentation
décrit les filtres disponibles.
Un build refait sous le même tag laisse-t-il une image pendante, c'est-à-dire
une image qui a perdu son nom ? Pas dans le cas mesuré. Le test ci-dessous
construit deux fois c35b-cache-img avec un contenu différent dans le démon
secondaire, puis liste les images, y compris les entrées cachées. La dernière
commande passe par ctr, le client en ligne de commande de containerd, qui lit
directement l'espace de noms c35b-ns du démon secondaire.
printf 'FROM %s\nRUN echo un > /f\n' "$IMAGE" > "$R/ctx/Dockerfile"sudo -E docker build --network none -q -t c35b-cache-img "$R/ctx"printf 'FROM %s\nRUN echo deux > /f\n' "$IMAGE" > "$R/ctx/Dockerfile"sudo -E docker build --network none -q -t c35b-cache-img "$R/ctx"sudo -E docker image ls --filter dangling=truesudo -E docker image ls -asudo ctr -n c35b-ns images ls -qIMAGE ID DISK USAGE CONTENT SIZE EXTRAIMAGE ID DISK USAGE CONTENT SIZE EXTRAalpine@sha256:ff7f0c727dd796aa36787bfcd9a64bf35a6ce72a73451b3359fde849b6703d63 ff7f0c727dd7 13MB 3.94MBc35b-cache-img:latest bb1e39de3365 12.9MB 3.86MBdocker.io/library/alpine@sha256:ff7f0c727dd796aa36787bfcd9a64bf35a6ce72a73451b3359fde849b6703d63docker.io/library/c35b-cache-img:latestSur Docker 29.9.2 avec le magasin containerd, le second build a déplacé le tag
sans laisser d'image pendante : la liste dangling=true ne contient que son
en-tête, docker image ls -a ne montre qu'un seul c35b-cache-img, et ctr
ne voit aucune entrée moby-dangling@. Ce constat vaut pour ce cas, un tag
déplacé par un build. Sur le démon système,
docker image ls --filter dangling=true reste la commande à lancer avant de
décider qu'une image est un rebut, et la liste y était vide.
La mesure est finie. Retirez les images du démon secondaire, puis revenez au
démon système avec unset DOCKER_HOST : sans lui, les commandes suivantes
continueraient de viser le démon secondaire. Arrêtez ensuite ce démon et
supprimez son dossier.
Il reste ses espaces de noms containerd, c35b-ns et c35b-ns_history. Ils
vivent dans le containerd du système, pas dans le dossier supprimé, et ctr
permet de les retirer. L'espace c35b-plug, réservé aux plugins, n'est jamais
apparu dans ctr namespaces ls pendant la mesure : il n'y a rien à retirer.
Un espace de noms ne se supprime que vide : la boucle ci-dessous retire d'abord
les baux (leases) qui retiennent les couches, puis les couches (snapshots) et
les blobs (content). Une fois la boucle terminée, ctr namespaces ls ne doit plus
lister ni c35b-ns ni c35b-ns_history.
sudo -E docker image rm c35b-cache-img "$IMAGE"unset DOCKER_HOSTsudo kill "$(cat "${R:?}/d.pid")"while [ -S "$R/d.sock" ]; do sleep 1; donesudo rm -rf "${R:?}"for ns in c35b-ns c35b-ns_history; do sudo ctr -n "$ns" leases ls -q | xargs -r -n1 sudo ctr -n "$ns" leases delete >/dev/null for i in $(seq 1 15); do [ "$(sudo ctr -n "$ns" snapshots ls | wc -l)" -le 1 ] && break sudo ctr -n "$ns" snapshots ls | awk 'NR>1{print $1}' | xargs -r -n1 sudo ctr -n "$ns" snapshots rm >/dev/null 2>&1 sleep 1 done sudo ctr -n "$ns" content ls -q | xargs -r sudo ctr -n "$ns" content rm >/dev/null sudo ctr namespaces rm "$ns"donesudo ctr namespaces lsComment supprimer seulement les ressources visées ?
Section intitulée « Comment supprimer seulement les ressources visées ? »Un conteneur arrêté et un volume détaché ne sont pas forcément des rebuts. La
démonstration a créé un conteneur arrêté portant un label, un autre conteneur
arrêté sans ce label et un conteneur qui utilise un volume nommé. Le filtre de
docker container prune n'a retiré que le conteneur portant le label demandé.
docker volume create c35b-data-refdocker run -d --name c35b-data-holder --network none \ --mount type=volume,src=c35b-data-ref,dst=/payload \ "$IMAGE" sh -c 'printf "stock=kept\n" > /payload/stock; sleep 7200'docker run --name c35b-stop-target --label c35b.cleanup=lesson --network none "$IMAGE" truedocker run --name c35b-stop-unrelated --network none "$IMAGE" true
docker container prune --filter label=c35b.cleanup=lesson --forcedocker inspect c35b-stop-unrelated \ --format 'unrelated_still_present={{.State.Status}}'docker inspect c35b-data-holder \ --format 'data_holder_still_present={{.State.Status}} volume={{range .Mounts}}{{.Name}}{{end}}'printf 'reference_data='docker exec c35b-data-holder cat /payload/stockdocker volume inspect c35b-data-ref --format 'named_volume={{.Name}}'Deleted Containers:3343f432a41bcf8f66fe4a4b3b39c4aa816e7bf98f89ca01439bf5699642bb93
Total reclaimed space: 4.096kBunrelated_still_present=exiteddata_holder_still_present=running volume=c35b-data-refreference_data=stock=keptnamed_volume=c35b-data-refLa sortie ne liste qu'un seul identifiant supprimé. Le conteneur arrêté sans
label et le volume nommé, avec ses données, sont restés en place. docker rm
suivi du nom d'un conteneur est encore plus précis : il ne vise que celui-là.
Avant d'élargir un filtre, lisez la
documentation.
Un volume anonyme, créé sans nom quand un conteneur déclare un chemin sans
source (ou quand l'image déclare une instruction VOLUME), peut rester après la
suppression de son conteneur. La démonstration l'a
retrouvé avec dangling=true (volumes qu'aucun conteneur n'utilise), puis l'a
supprimé par son nom exact. Un volume nommé se supprime de la même façon, après
avoir vérifié qu'aucun conteneur utile ne l'utilise.
docker run --name c35b-anon-owner --network none --volume /cache "$IMAGE" \ sh -c 'printf "discard\n" > /cache/item'ANON_VOLUME=$(docker inspect c35b-anon-owner \ --format '{{range .Mounts}}{{if eq .Destination "/cache"}}{{.Name}}{{end}}{{end}}')docker rm c35b-anon-ownerdocker volume ls --filter dangling=truedocker volume rm "$ANON_VOLUME"docker system prune retire, à l'échelle du démon, les conteneurs arrêtés,
les réseaux inutilisés, les images pendantes et le cache de construction. Avec
-a, il supprime aussi les images qu'aucun conteneur n'utilise, et --volumes
ajoute les volumes anonymes inutilisés. L'option --volumes met
des données en danger, parce qu'un volume anonyme peut en porter : une image dont
le Dockerfile déclare un VOLUME en crée un à chaque conteneur, et ce volume
peut contenir une base de données que personne n'a nommée. Le
guide des volumes montre
comment les repérer. Cette portée large ne remplace pas un inventaire des
données à conserver : n'en faites pas un geste de routine. La commande n'a pas
été exécutée pendant la mesure ; la
documentation
liste les ressources concernées.
Où se trouve ENOSPC, et comment libérer l'espace sans recréer ?
Section intitulée « Où se trouve ENOSPC, et comment libérer l'espace sans recréer ? »ENOSPC est l'erreur « No space left on device » : une écriture n'a plus de
place. Le refus peut venir de la couche d'écriture du conteneur, d'un tmpfs
(un système de fichiers en mémoire, à taille plafonnée), d'un volume ou du
système de fichiers de l'hôte. Pour trouver lequel, docker inspect montre les
montages et les limites tmpfs, df -h mesure les octets et df -i mesure
les inodes, c'est-à-dire les entrées nécessaires pour créer des fichiers.
La démonstration a attaché un tmpfs de 2 Mio à /scratch et le volume nommé à
/persistent. Elle a écrit une donnée témoin dans le volume, puis inspecté les
montages et comparé les systèmes de fichiers.
docker run -d --name c35b-tmpfs-space --network none \ --mount type=volume,src=c35b-data-ref,dst=/persistent \ --tmpfs /scratch:rw,size=2m,nr_inodes=64 \ "$IMAGE" sleep 7200docker exec c35b-tmpfs-space sh -c 'printf "inventory-line\n" > /persistent/inventory'SPACE_ID=$(docker inspect c35b-tmpfs-space --format '{{.Id}}')docker inspect c35b-tmpfs-space \ --format 'container_id={{.Id}} tmpfs={{json .HostConfig.Tmpfs}} mounts={{json .Mounts}}'docker exec c35b-tmpfs-space df -h / /scratch /persistentdocker exec c35b-tmpfs-space df -i /scratchDOCKER_ROOT=$(docker info --format '{{.DockerRootDir}}')df -h "$DOCKER_ROOT"df -i "$DOCKER_ROOT"Filesystem Size Used Available Use% Mounted onoverlay 19.5G 2.1G 16.5G 11% /tmpfs 2.0M 0 2.0M 0% /scratch/dev/vda1 19.5G 2.1G 16.5G 11% /persistentFilesystem Inodes Used Available Use% Mounted ontmpfs 64 1 63 2% /scratchFilesystem Size Used Avail Use% Mounted on/dev/vda1 20G 2.2G 17G 12% /Filesystem Inodes IUsed IFree IUse% Mounted on/dev/vda1 1302528 51235 1251293 4% /Lisez les montages un par un. /scratch est un tmpfs de 2,0 M, avec 64 inodes.
/persistent affiche le même disque /dev/vda1 que l'hôte : un volume nommé
consomme ici le disque de l'hôte, alors que le tmpfs a sa propre limite. Le
disque hôte n'a pas été rempli. Identifiez d'abord le montage plein, puis
retirez seulement le fichier que vous avez confirmé jetable.
Le test a écrit dans /scratch jusqu'à atteindre exactement la limite. dd
a rendu le code 1, alors que df -i montrait encore 62 inodes disponibles :
les octets étaient épuisés, pas les inodes.
if docker exec c35b-tmpfs-space sh -c \ 'dd if=/dev/zero of=/scratch/discard.bin bs=64k count=40'; then echo 'fill_exit=0'else printf 'fill_exit=%s\n' "$?"fidocker exec c35b-tmpfs-space df -h /scratchdocker exec c35b-tmpfs-space df -i /scratchdocker exec c35b-tmpfs-space rm /scratch/discard.bindocker exec c35b-tmpfs-space df -h /scratchdocker exec c35b-tmpfs-space sh -c \ 'dd if=/dev/zero of=/scratch/new-write.bin bs=64k count=1'docker exec c35b-tmpfs-space stat -c 'new_write_bytes=%s' /scratch/new-write.binprintf 'useful_volume_data='docker exec c35b-tmpfs-space cat /persistent/inventoryprintf 'same_container_id='test "$(docker inspect c35b-tmpfs-space --format '{{.Id}}')" = "$SPACE_ID" && echo yesdocker inspect c35b-tmpfs-space --format 'tmpfs_after={{json .HostConfig.Tmpfs}}'dd: error writing '/scratch/discard.bin': No space left on device33+0 records in32+0 records out2097152 bytes (2.0MB) copied, 0.000495 seconds, 3.9GB/sfill_exit=1Filesystem Size Used Available Use% Mounted ontmpfs 2.0M 2.0M 0 100% /scratchFilesystem Inodes Used Available Use% Mounted ontmpfs 64 2 62 3% /scratchFilesystem Size Used Available Use% Mounted ontmpfs 2.0M 0 2.0M 0% /scratch1+0 records in1+0 records out65536 bytes (64.0KB) copied, 0.000071 seconds, 880.3MB/snew_write_bytes=65536useful_volume_data=inventory-linesame_container_id=yestmpfs_after={"/scratch":"rw,size=2m,nr_inodes=64"}Après rm, /scratch est repassé à 0 octet utilisé et une nouvelle écriture de
65 536 octets a réussi. L'identifiant du conteneur est resté inchangé, son
plafond de 2 Mio n'a pas bougé et le volume nommé est resté lisible. Retirer
le fichier jetable a suffi, sans recréer le conteneur.
Le cas inverse existe : un système de fichiers peut manquer d'inodes alors que
des octets restent libres. Dans un second tmpfs de 8 Mio limité à huit
inodes, sept fichiers ont été créés, puisque le répertoire racine du tmpfs
consomme lui-même un inode ; le huitième a échoué, tandis que df -h
affichait toujours 8 Mio disponibles.
docker run -d --name c35b-tmpfs-inodes --network none \ --tmpfs /small:rw,size=8m,nr_inodes=8 \ "$IMAGE" sleep 7200docker exec c35b-tmpfs-inodes sh -c \ 'i=0; while [ "$i" -lt 32 ]; do if ! touch "/small/f$i"; then printf "create_failed_at=%s\n" "$i"; break; fi; i=$((i+1)); done; printf "files_created=%s\n" "$i"; df -h /small; df -i /small'touch: /small/f7: No space left on devicecreate_failed_at=7files_created=7Filesystem Size Used Available Use% Mounted ontmpfs 8.0M 0 8.0M 0% /smallFilesystem Inodes Used Available Use% Mounted ontmpfs 8 8 0 100% /smallDans la sortie, df -h annonce 8,0 M disponibles, et df -i montre 8 inodes
utilisés sur 8. Quand df -h montre de l'espace libre mais que la création d'un
fichier échoue, regardez donc aussi df -i. Ne remplissez jamais une partition
de l'hôte pour reproduire un disque plein : utilisez un système de fichiers
borné.
Quand le plein est sur l'hôte lui-même, la démarche ne change pas, mais les
outils sont ceux de Linux. Le guide
Contrôler l'espace disque et les inodes
détaille df, du et la lecture des inodes. Il existe aussi un piège que cette
leçon n'a pas mesuré : un fichier supprimé reste sur le disque tant qu'un
processus le garde ouvert, si bien que du compte moins d'octets que df. Le
guide
Contrôler capacité et quotas disque
montre comment retrouver ce processus.
Comment nettoyer la démonstration ?
Section intitulée « Comment nettoyer la démonstration ? »Retirez d'abord les ressources Docker créées pour la leçon. Vérifiez que le
dossier ~/journaux-disque ne contient que les fichiers de cette démonstration
avant de supprimer son contenu. Le démon secondaire est déjà arrêté depuis la
section sur la mesure de l'espace.
IMAGE="alpine:3.23@sha256:ff7f0c727dd796aa36787bfcd9a64bf35a6ce72a73451b3359fde849b6703d63"IMAGE="$IMAGE" docker compose -p c35b-log-compose \ -f "$HOME/journaux-disque/compose/compose.yaml" down
for name in c35b-log-open c35b-log-capped c35b-log-local c35b-data-holder \ c35b-stop-unrelated c35b-tmpfs-space c35b-tmpfs-inodes; do docker rm -f "$name"donedocker volume rm c35b-data-refdocker image rm "$IMAGE"
cd ~find "$HOME/journaux-disque" -depth -deleteCette séquence a supprimé uniquement les conteneurs, le volume, l'image et le dossier créés pour la leçon. Les ressources qui existaient avant la leçon restent en place : chaque commande vise un nom, jamais une catégorie entière.
Mettre en pratique
Section intitulée « Mettre en pratique »Le premier lab demande de borner le journal d'un service identifié. Ses tests contrôlent le pilote et les options déclarées, puis la rotation effective : les lignes les plus anciennes doivent avoir été jetées et le volume retenu doit tenir dans le budget que ces bornes définissent. Le service doit aussi rester actif. Il utilise des valeurs et un conteneur différents de ceux de la démonstration.
Le second lab fait diagnostiquer un espace borné et retirer un fichier
jetable. Ses tests vérifient que le conteneur d'origine et les données utiles
restent en place, que l'espace borné reste un tmpfs de 16 Mio sans avoir été
agrandi, que le fichier jetable a disparu, puis qu'une nouvelle écriture réussit.
À retenir
Section intitulée « À retenir »Une reprise fiable commence par l'identification de la ressource pleine et de son propriétaire.
- Vous vérifiez la rotation sur les fichiers de l'hôte, pas seulement dans
HostConfig.LogConfig, et vous savez que les lignes au-delà demax-filesont perdues. - Les options de journal se fixent à la création du conteneur, et les
log-optsdedaemon.jsonne valent que pour les nouveaux conteneurs : vous recréez un conteneur pour qu'il les hérite. - Vous inspectez les catégories avec
docker system dfavant toute suppression. NiRECLAIMABLEni leTotaldeprunene donnent l'espace rendu : le premier ignore les couches partagées, le second additionne des entrées. Seuldf, relevé avant et après, le mesure. - Vous filtrez les conteneurs arrêtés et vous supprimez un volume par son nom
seulement après avoir vérifié ses données.
docker system pruneagit sur tout le démon, et--volumespeut effacer un volume anonyme qui porte des données. - Vous lisez
df -hetdf -iensemble avant de conclure qu'un système de fichiers est plein : les octets et les inodes s'épuisent séparément. - Vous libérez un fichier jetable sans recréer le conteneur quand son plafond reste inchangé.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de cette leçon est acquis. Les questions portent sur les choix de configuration, le diagnostic d'un disque plein et la portée des nettoyages.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Mettre à jour le moteur et sauvegarder sa configuration
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications