Docker-Tipps: Befreien Sie Ihre Maschine von Müll

Docker-Tipps: Befreien Sie Ihre Maschine von Müll

Hey Habr! Ich präsentiere Ihnen die Übersetzung des Artikels „Docker-Tipps: Bereinigen Sie Ihren lokalen Computer“ Autor Luc Juggery.

Heute werden wir darüber sprechen, wie Docker den Speicherplatz des Host-Computers nutzt, und wir werden auch herausfinden, wie dieser Speicherplatz von den Resten ungenutzter Bilder und Container befreit werden kann.


Docker-Tipps: Befreien Sie Ihre Maschine von Müll

Gesamtverbrauch

Docker ist eine coole Sache, wahrscheinlich zweifeln heute nur wenige daran. Noch vor wenigen Jahren eröffnete uns dieses Produkt eine völlig neue Möglichkeit, beliebige Umgebungen zu erstellen, bereitzustellen und auszuführen, wodurch wir CPU- und RAM-Ressourcen erheblich einsparen konnten. Darüber hinaus (und für einige wird dies das Wichtigste sein) hat uns Docker ermöglicht, das Lebenszyklusmanagement unserer Produktionsumgebungen unglaublich zu vereinfachen und zu vereinheitlichen.

Allerdings haben all diese Freuden des modernen Lebens ihren Preis. Wenn wir Container betreiben, unsere eigenen Images herunterladen oder erstellen und komplexe Ökosysteme bereitstellen, müssen wir bezahlen. Und wir bezahlen unter anderem mit Speicherplatz.

Wenn Sie noch nie darüber nachgedacht haben, wie viel Speicherplatz Docker tatsächlich auf Ihrem Computer einnimmt, werden Sie möglicherweise von der Ausgabe dieses Befehls unangenehm überrascht sein:

$ docker system df

Docker-Tipps: Befreien Sie Ihre Maschine von Müll

Dies zeigt die Festplattennutzung von Docker in verschiedenen Kontexten:

  • Bilder – die Gesamtgröße der Bilder, die aus Bild-Repositorys heruntergeladen und auf Ihrem System erstellt wurden;
  • Container – die Gesamtmenge an Speicherplatz, die von der Ausführung von Containern genutzt wird (d. h. das Gesamtvolumen der Lese-/Schreibebenen aller Container);
  • lokale Volumes – das Volumen des lokalen Speichers, der in Containern bereitgestellt wird;
  • Build-Cache – temporäre Dateien, die durch den Image-Erstellungsprozess generiert werden (mit dem BuildKit-Tool, verfügbar ab Docker-Version 18.09).

Ich wette, dass Sie nach dieser einfachen Übertragung unbedingt Ihre Festplatte von Müll befreien und wertvolle Gigabyte wieder zum Leben erwecken möchten (Hinweis: Vor allem, wenn Sie jeden Monat Miete für diese Gigabyte zahlen).

Festplattennutzung durch Container

Jedes Mal, wenn Sie einen Container auf dem Host-Computer erstellen, werden mehrere Dateien und Verzeichnisse im Verzeichnis /var/lib/docker erstellt, von denen die folgenden erwähnenswert sind:

  • Verzeichnis /var/lib/docker/containers/container_ID – bei Verwendung des Standardprotokollierungstreibers werden hier Ereignisprotokolle im JSON-Format gespeichert. Zu detaillierte Protokolle sowie Protokolle, die niemand liest oder anderweitig verarbeitet, führen oft dazu, dass die Festplatten voll werden.
  • Das Verzeichnis /var/lib/docker/overlay2 enthält die Lese-/Schreibebenen des Containers (overlay2 ist der bevorzugte Treiber in den meisten Linux-Distributionen). Wenn der Container Daten in seinem Dateisystem speichert, werden sie in diesem Verzeichnis abgelegt.

Stellen wir uns ein System vor, auf dem ein makelloser Docker installiert ist, der noch nie daran beteiligt war, Container zu starten oder Images zu erstellen. Der Bericht zur Speicherplatznutzung sieht folgendermaßen aus:

$ 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

Lassen Sie uns einen Container starten, zum Beispiel NGINX:

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

Was passiert mit der Festplatte:

  • Bilder belegen 126 MB. Dies ist derselbe NGINX, den wir im Container gestartet haben.
  • Container nehmen lächerliche 2 Bytes ein.

$ 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

Dem Fazit nach zu urteilen, haben wir noch keinen Platz, den wir freimachen könnten. Da 2 Bytes völlig unseriös sind, stellen wir uns vor, dass unser NGINX unerwartet irgendwo 100 Megabyte Daten geschrieben und in sich selbst eine Datei test.img mit genau dieser Größe erstellt hat.

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

Schauen wir uns noch einmal die Speicherplatznutzung auf dem Host an. Wir werden sehen, dass der Container (die Container) dort 100 Megabyte belegt.

$ 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

Ich denke, Ihr neugieriges Gehirn fragt sich bereits, wo sich unsere test.img-Datei befindet. Suchen wir danach:

$ 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

Ohne auf Details einzugehen, können wir feststellen, dass sich die Datei test.img bequem auf der Lese-/Schreibebene befindet und vom Overlay2-Treiber gesteuert wird. Wenn wir unseren Container stoppen, teilt uns der Host mit, dass dieser Platz grundsätzlich freigegeben werden kann:

# 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

Wie können wir das machen? Durch Löschen des Containers, was die Freigabe des entsprechenden Speicherplatzes auf der Lese-/Schreibebene zur Folge hat.

Mit dem folgenden Befehl können Sie alle installierten Container auf einen Schlag entfernen und Ihre Festplatte von allen von ihnen erstellten Lese-/Schreibdateien befreien:

$ 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

Durch das Löschen des Containers haben wir also 104,9 Megabyte freigegeben. Da wir das zuvor heruntergeladene Bild jedoch nicht mehr verwenden, wird es auch zu einem Kandidaten für das Löschen und Freigeben unserer Ressourcen:

$ 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

Hinweis: Solange das Image von mindestens einem Container verwendet wird, können Sie diesen Trick nicht anwenden.

Der oben verwendete Unterbefehl prune hat nur Auswirkungen auf gestoppte Container. Wenn wir nicht nur gestoppte, sondern auch laufende Container löschen möchten, sollten wir einen dieser Befehle verwenden:

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

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

Randbemerkung: Wenn Sie beim Starten eines Containers den Parameter -rm verwenden, wird beim Stoppen der gesamte von ihm belegte Speicherplatz freigegeben.

Verwenden von Disk-Images

Vor einigen Jahren war eine Bildgröße von mehreren hundert Megabyte völlig normal: Ein Ubuntu-Image wog 600 Megabyte und ein Microsoft .Net-Image mehrere Gigabyte. In diesen schwierigen Zeiten konnte das Herunterladen nur eines Bildes Ihren freien Speicherplatz stark beanspruchen, selbst wenn Sie Ebenen zwischen Bildern teilten. Heutzutage – Lob gebührt den Großen – wiegen Bilder viel weniger, aber trotzdem kann man die verfügbaren Ressourcen schnell auffüllen, wenn man nicht einige Vorsichtsmaßnahmen trifft.

Es gibt verschiedene Arten von Bildern, die für den Endbenutzer nicht direkt sichtbar sind:

  • Zwischenbilder, auf deren Grundlage andere Bilder gesammelt werden – sie können nicht gelöscht werden, wenn Sie Container verwenden, die auf diesen „anderen“ Bildern basieren;
  • Baumelnde Bilder sind Zwischenbilder, auf die von keinem der laufenden Container verwiesen wird – sie können gelöscht werden.
  • Mit dem folgenden Befehl können Sie nach freien Bildern auf Ihrem System suchen:

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

Sie können sie auf folgende Weise entfernen:

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

Wir können auch den Unterbefehl prune verwenden:

$ 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

Wenn wir plötzlich mit einem Befehl alle Bilder insgesamt (und nicht nur die baumelnden) löschen möchten, können wir Folgendes tun:

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

Festplattennutzung nach Volumes

Volumes werden zum Speichern von Daten außerhalb des Dateisystems des Containers verwendet. Zum Beispiel, wenn wir die Ergebnisse einer Anwendung speichern möchten, um sie anderweitig zu verwenden. Ein häufiges Beispiel sind Datenbanken.

Starten wir einen MongoDB-Container, mounten ein Volume außerhalb des Containers und stellen daraus eine Datenbanksicherung wieder her (wir haben sie in der Datei bck.json verfügbar):

# 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

Die Daten befinden sich auf dem Host-Computer im Verzeichnis /var/lib/docker/volumes. Aber warum nicht auf der Lese-/Schreibebene des Containers? Denn im Dockerfile des MongoDB-Images ist das Verzeichnis /data/db (in dem MongoDB seine Daten standardmäßig speichert) als Volume definiert.

Docker-Tipps: Befreien Sie Ihre Maschine von Müll

Randbemerkung: Viele Bilder, die Daten erzeugen müssen, verwenden Volumes zum Speichern dieser Daten.

Wenn wir genug mit MongoDB spielen und den Container stoppen (oder vielleicht sogar löschen), wird das Volume nicht gelöscht. Es wird weiterhin unseren wertvollen Speicherplatz beanspruchen, bis wir es explizit mit einem Befehl wie diesem löschen:

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

Nun ja, oder wir können den uns bereits bekannten Unterbefehl prune verwenden:

$ 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:~$

Verwenden der Festplatte für den Image-Build-Cache

In Docker 18.09 hat der Image-Erstellungsprozess dank des BuildKit-Tools einige Änderungen erfahren. Dies erhöht die Geschwindigkeit des Prozesses und optimiert die Datenspeicherung und das Sicherheitsmanagement. Hier werden wir nicht alle Details dieses wunderbaren Tools betrachten; wir werden uns nur darauf konzentrieren, wie es Probleme bei der Speicherplatznutzung angeht.

Nehmen wir an, wir haben eine völlig einfache Node.Js-Anwendung:

  • Die Datei index.js startet einen einfachen HTTP-Server, der auf jede empfangene Anfrage mit einer Zeile antwortet:
  • Die Datei package.json definiert die Abhängigkeiten, von denen nur expressjs zum Ausführen des HTTP-Servers verwendet wird:

$ 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"
      }
    }

Die Docker-Datei zum Erstellen des Images sieht folgendermaßen aus:

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

Lassen Sie uns das Image wie gewohnt erstellen, ohne BuildKit zu verwenden:

$ docker build -t app:1.0 .

Wenn wir die Speicherplatznutzung überprüfen, können wir sehen, dass nur das Basis-Image (node:13-alpine) und das Ziel-Image (app:1.0) Speicherplatz beanspruchen:

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

Lassen Sie uns mit BuildKit die zweite Version unserer Anwendung erstellen. Dazu müssen wir lediglich die Variable DOCKER_BUILDKIT auf 1 setzen:

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

Wenn wir nun die Festplattennutzung überprüfen, werden wir feststellen, dass dort nun der Build-Cache (buid-cache) beteiligt ist:

$ 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

Um es zu löschen, verwenden Sie den folgenden Befehl:

$ 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

Alles löschen!

Deshalb haben wir uns mit der Bereinigung des von Containern, Bildern und Volumes belegten Speicherplatzes beschäftigt. Dabei hilft uns der Unterbefehl prune. Es kann aber auch auf Docker-Systemebene verwendet werden und bereinigt alles, was es kann:

$ 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]

Wenn Sie aus irgendeinem Grund Speicherplatz auf einem Computer sparen, auf dem Docker ausgeführt wird, sollte es Ihnen zur Gewohnheit werden, diesen Befehl regelmäßig auszuführen.

Source: habr.com

Kommentar hinzufügen