Docker-Tipps: Bereinigen Sie Ihren Rechner von unnötigem Ballast

Docker-Tipps: Bereinigen Sie Ihren Rechner von unnötigem Ballast

Hallo, Habr! Ich präsentiere Ihnen eine Übersetzung des Artikels. "Docker-Tipps: Bereinigen Sie Ihre lokale Maschine" Autor Luc Juggery.

Heute sprechen wir darüber, wie Docker den Speicherplatz des Hostsystems nutzt und wie wir diesen Platz von Überresten ungenutzter Images und Container befreien können.


Docker-Tipps: Bereinigen Sie Ihren Rechner von unnötigem Ballast

Gesamtverbrauch

Docker ist eine großartige Sache, das bezweifelt wahrscheinlich heute kaum jemand. Vor ein paar Jahren hat dieses Produkt uns einen völlig neuen Weg eröffnet, jede Umgebung zu erstellen, zu liefern und zu starten, wodurch Ressourcen des Prozessors und des Arbeitsspeichers erheblich eingespart werden konnten. Zusätzlich dazu (und das ist für einige vielleicht sogar das Wichtigste) hat Docker es uns ermöglicht, das Management des Lebenszyklus genutzter Arbeitsumgebungen unglaublich zu vereinfachen und zu standardisieren.

Allerdings hat man für all die Vorteile des modernen Lebens auch einen Preis zu zahlen. Wenn wir Container starten, eigene Images herunterladen oder erstellen und komplexe Ökosysteme aufbauen, müssen wir dafür bezahlen. Und zwar bezahlen wir unter anderem mit Speicherplatz.

Wenn Sie sich jemals gefragt haben, wie viel Speicher wirklich von Ihrem Docker auf Ihrem Rechner belegt wird, könnten Sie von der Ausgabe dieses Befehls unangenehm überrascht sein:

$ docker system df

Docker-Tipps: Bereinigen Sie Ihren Rechner von unnötigem Ballast

Hier wird die Nutzung des Speichers durch Docker in verschiedenen Kategorien angezeigt:

  • Images – Gesamter Speicherplatz der Images, die aus Registries heruntergeladen und in Ihrem System erstellt wurden;
  • Container – Gesamter Speicherplatz, der von laufenden Containern verwendet wird (gemeint ist das gesamte Volumen der Schreib-Lese-Schichten aller Container);
  • Lokale Volumes – Umfang der lokalen Speicher, die an Container angehängt sind;
  • Baucache – temporäre Dateien, die während des Erstellens von Images generiert wurden (beim Einsatz des BuildKit-Tools, das seit Docker Version 18.09 verfügbar ist).

Ich wette, dass Sie schon nach dieser einfachen Aufzählung den Drang verspüren, die Festplatte von Müll zu befreien und wertvolle Gigabyte zurückzugewinnen (Anmerkung des Übersetzers: besonders, wenn Sie für diese Gigabyte monatlich Miete zahlen).

Speicherplatznutzung durch Container

Jedes Mal, wenn ein Container auf dem Hostsystem erstellt wird, werden im Verzeichnis /var/lib/docker mehrere Dateien und Verzeichnisse angelegt, von denen nachfolgend einige hervorgehoben werden:

  • Das Verzeichnis /var/lib/docker/containers/ID_des_Containers – wenn der standardmäßige Logging-Treiber verwendet wird, werden die Ereignisprotokolle im JSON-Format genau hier gespeichert. Zu detaillierte Protokolle sowie Protokolle, die niemand liest oder auf andere Weise verarbeitet, sind häufig die Ursache für das Überlaufen von Festplatten.
  • Das Verzeichnis /var/lib/docker/overlay2 – enthält die schreibbaren Schichten der Container (overlay2 – der bevorzugte Treiber in den meisten Linux-Distributionen). Wenn ein Container Daten in seinem Dateisystem speichert, werden diese genau in diesem Verzeichnis abgelegt.

Stellen wir uns ein System vor, auf dem ein jungfräulicher Docker installiert ist, der noch nie Container oder Images gestartet hat. Sein Bericht über den Festplattenspeicher wird folgendermaßen aussehen:

$ 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

Starten wir einen Container, beispielsweise NGINX:

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

Was passiert mit der Festplatte:

  • Images (Abbilder) belegen 126 MB, das ist das NGINX, das wir im Container gestartet haben;
  • Container belegen lächerliche 2 Bytes.

$ 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

Laut der Ausgabe haben wir noch keinen Speicherplatz, den wir freigeben könnten. Da 2 Bytes völlig unbedeutend sind, lassen Sie uns vorstellen, dass unser NGINX überraschend 100 Megabyte Daten irgendwo geschrieben hat und darin eine Datei test.img genau dieser Größe erstellt hat.

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

Untersuchen wir erneut die Festplattennutzung auf dem Host. Wir werden sehen, dass der 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 unsere Datei test.img ist. Lassen Sie uns danach suchen:

$ 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 ins Detail zu gehen, kann festgestellt werden, dass die Datei test.img günstig auf der Lese-Schreib-Ebene platziert ist, die vom Treiber overlay2 verwaltet wird. Wenn wir unseren Container jedoch anhalten, wird der Host uns darauf hinweisen, dass dieser Speicherplatz 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 tun? Durch das Löschen des Containers, was die Bereinigung des entsprechenden Speicherplatzes auf der Lese-Schreib-Ebene nach sich zieht.

Mit dem folgenden Befehl können Sie alle installierten Container auf einmal löschen und Ihre Festplatte von allen durch diese erzeugten Lese-Schreib-Dateien bereinigen:

$ docker container prune
WARNING! Dies entfernt alle gestoppten Container.
Sind Sie sicher, dass Sie fortfahren möchten? [y/N] y
Gelöschte Container:
5e7f8e5097ace9ef5518ebf0c6fc2062ff024efb495f11ccc89df21ec9b4dcc2

Insgesamt zurückgewonnener Speicherplatz: 104,9 MB

Damit haben wir 104,9 Megabyte durch das Löschen des Containers freigegeben. Da wir jedoch das zuvor heruntergeladene Image nicht mehr verwenden, wird auch dieses zum Kandidaten für die Löschung und für die Freisetzung 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

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

Der Befehl prune, den wir oben verwendet haben, hat nur Wirkung auf gestoppte Container. Wenn wir sowohl gestoppte als 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)

Hinweis am Rande: Wenn Sie beim Starten des Containers die Option —rm verwenden, wird bei dessen Stopp der gesamte Speicherplatz freigegeben, den er belegt hat.

Speichernutzung durch Images

Vor einigen Jahren war die Größe eines Images von mehreren Hundert Megabyte völlig normal: Das Ubuntu-Image wog 600 Megabyte, und das Microsoft .Net-Image mehrere Gigabyte. In diesen alten Zeiten konnte der Download selbst eines einzigen Images großen Schaden an Ihrem verfügbaren Speicherplatz anrichten, selbst wenn Sie die Ebenen zwischen Images geteilt haben. Heute – Dank der Götter – wiegen die Images viel weniger, aber selbst in diesem Fall kann man schnell die vorhandenen Ressourcen überlasten, wenn man keine Vorsichtsmaßnahmen trifft.

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

  • Intermediäre Images, auf deren Grundlage andere Images erstellt wurden – sie können nicht gelöscht werden, wenn Sie Container auf der Basis dieser "anderen" Images verwenden;
  • Hängende Images – das sind solche intermediären Images, auf die keiner der laufenden Container verweist – sie können gelöscht werden.
  • Mit dem folgenden Befehl können Sie in Ihrem System nach hängenden Images suchen:

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

Sie können sie folgendermaßen löschen:

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

Wir können auch den Unterbefehl prune verwenden:

$ docker image prune
WARNUNG! Dies wird alle hängenden Images entfernen.
Sind Sie sicher, dass Sie fortfahren möchten? [y/N] y
Gelöschte Images:
gelöscht: sha256:143407a3cb7efa6e95761b8cd6cea25e3f41455be6d5e7cda
gelöscht: sha256:738010bda9dd34896bac9bbc77b2d60addd7738ad1a95e5cc
gelöscht: sha256:fa4f0194a1eb829523ecf3bad04b4a7bdce089c8361e2c347
gelöscht: sha256:c5041938bcb46f78bf2f2a7f0a0df0eea74c4555097cc9197
gelöscht: sha256:5945bb6e12888cf320828e0fd00728947104da82e3eb4452f

Insgesamt wiedergewonnener Speicherplatz: 12,9 kB

Falls wir ausnahmsweise alle Images (nicht nur hängende) mit einem Befehl löschen möchten, können wir es so machen:

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

Verwendung von Speicherplatz durch Volumes

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

Lassen Sie uns einen MongoDB-Container starten, ein externes Volume montieren und ein Backup der Datenbank aus der Datei bck.json wiederherstellen:

# 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 werden auf der Host-Maschine im Verzeichnis /var/lib/docker/volumes gespeichert. Aber warum nicht im Container im Lese-Schreib-Zugriff? Weil im Dockerfile des MongoDB-Images das Verzeichnis /data/db (in dem MongoDB standardmäßig seine Daten speichert) als Volume definiert ist.

Docker-Tipps: Bereinigen Sie Ihren Rechner von unnötigem Ballast

Hinweise: Viele Images, aus deren Verarbeitung Daten entstehen sollten, verwenden Volumes zur Speicherung dieser Daten.

Wenn wir mit MongoDB fertig sind und den Container stoppen (oder vielleicht sogar löschen), wird das Volume nicht gelöscht. Es wird weiterhin unser wertvolles Speicherplatz belegen, bis wir es ausdrücklich mit folgendem Befehl löschen:

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

Oder wir können den uns bereits bekannten Unterbefehl prune verwenden:

$ docker volume prune
WARNUNG! Dies entfernt alle lokalen Volumes, die nicht von mindestens einem Container verwendet werden.
Sind Sie sicher, dass Sie fortfahren möchten? [y/N] y
Gelöschte Volumes:
d50b6402eb75d09ec17a5f57df4ed7b520c448429f70725fc5707334e5ded4d5
8f7a16e1cf117cdfddb6a38d1f4f02b18d21a485b49037e2670753fa34d115fc
599c3dd48d529b2e105eec38537cd16dac1ae6f899a123e2a62ffac6168b2f5f
...
732e610e435c24f6acae827cd340a60ce4132387cfc512452994bc0728dd66df
9a3f39cc8bd0f9ce54dea3421193f752bda4b8846841b6d36f8ee24358a85bae
045a9b534259ec6c0318cb162b7b4fca75b553d4e86fc93faafd0e7c77c79799
c6283fe9f8d2ca105d30ecaad31868410e809aba0909b3e60d68a26e92a094da

Gesamter zurückgewonnener Speicherplatz: 25,82 GB
luc@saturn:~$

Verwendung des Speichers für den Cache beim Erstellen von Images

In Docker 18.09 hat der Prozess zur Erstellung von Images einige Änderungen erfahren, dank des Tools BuildKit. Dieses Tool erhöht die Geschwindigkeit des Prozesses und optimiert die Verwaltung von Datenspeicherung und Sicherheit. Hier werden wir nicht alle Details dieses bemerkenswerten Werkzeugs betrachten, sondern uns lediglich ansehen, wie es die Nutzung des Speicherplatzes beeinflusst.

Angenommen, wir haben eine ganz einfache Node.Js-Anwendung:

  • Die Datei index.js startet einen einfachen HTTP-Server, der auf jede eingehende Anfrage mit einer Zeile antwortet:
  • Die Datei package.json definiert die Abhängigkeiten, von denen nur expressjs zur Ausführung 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"
      }
    }

Das Dockerfile 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 auf herkömmliche Weise ohne Verwendung von BuildKit erstellen:

$ docker build -t app:1.0 .

Wenn wir die Nutzung des Speicherplatzes überprüfen, sehen wir, dass nur das Basisimage (node:13-alpine) und das endgültige Image (app:1.0) Platz 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 die zweite Version unserer Anwendung erstellen, nun mit Verwendung von BuildKit. Dazu müssen wir lediglich die Umgebungsvariable DOCKER_BUILDKIT auf 1 setzen:

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

Wenn wir jetzt die Nutzung des Speichers überprüfen, sehen wir, dass jetzt der Build-Cache (build-cache) beteiligt ist:

$ docker system df
TYPE           TOTAL      ACTIVE     SIZE       RECLAIMBAR
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 ihn zu bereinigen, verwenden wir den folgenden Befehl:

$ docker builder prune
WARNUNG! Dies entfernt allen nicht mehr verwendeten Build-Cache.
Sind Sie sicher, dass Sie fortfahren möchten? [y/N] y
Gelöschte Build-Cache-Objekte:
rffq7b06h9t09xe584rn4f91e
ztexgsz949ci8mx8p5tzgdzhe
3z9jeoqbbmj3eftltawvkiayi

Gesamt wiederhergestellter Speicherplatz: 8.949kB

Alles bereinigen!

Wir haben also die Bereinigung des Festplattenspeichers betrachtet, der von Containern, Images und Volumes belegt wird. Dabei hilft uns der Unterbefehl prune. Dieser kann jedoch auch auf Systemebene von Docker verwendet werden und bereinigt alles, was er kann:

$ docker system prune
WARNUNG! Dies entfernt:
  - alle gestoppten Container
  - alle Netzwerke, die von mindestens einem Container nicht verwendet werden
  - alle nicht mehr verwendeten Images
  - allen nicht mehr verwendeten Build-Cache

Sind Sie sicher, dass Sie fortfahren möchten? [y/N]

Wenn Sie aus irgendeinem Grund Speicherplatz auf Ihrem Docker-Rechner sparen, sollten Sie sich angewöhnen, diesen Befehl regelmäßig auszuführen.

Quelle: habr.com

60GB SSD 8Gb DDR4