Sechs Möglichkeiten, die Größe von Docker-Images zu reduzieren

Sechs Möglichkeiten, die Größe von Docker-Images zu reduzieren

Seitdem ich 2017 mit der Arbeit an Vulhub begonnen habe, kämpfe ich mit einem lästigen Problem: Wie kann ich beim Schreiben einer Docker-Datei die Größe des vom docker build generierten Images reduzieren ? Dieser Artikel fasst sechs Methoden zusammen, die ich zum Reduzieren der Bildgröße verwendet habe.

1. Verwenden von Alpine Linux

Alpine Linux ist eine Linux-Distribution, die auf BusyBox und Musl Libc basiert. Ihr größter Vorteil ist ihre geringe Größe. Ein reines Basis-Alpine-Docker-Image ist komprimiert nur 2,67 MB groß.

Viele offizielle Docker-Images haben Alpine-Versionen, beispielsweise PHP:

Im Vergleich dazu ist festzustellen, dass die Größe des Bildes der alpinen Version etwa 1/5 der normalen Version beträgt.

Allerdings gibt es im Docker Hub für die meisten Images keine Alpine-Versionen, wie etwa Mysql und PHP-Apache. Wenn wir auf der Grundlage dieser Umgebungen entwickeln müssen, müssen wir selbst Alpine-Versionen schreiben oder Images von Drittanbietern finden.

Darüber hinaus besteht ein weiterer Nachteil von Alpine darin, dass es Musl Libc als Ersatz für das herkömmliche glibc verwendet. Beim Kompilieren der Software können unvorhersehbare Probleme auftreten, die uns unnötig viel Zeit kosten.

2. Installieren Sie nur minimale Abhängigkeiten

Paketmanager wie apt-get, yum und apk sind Tools, die wir beim Kompilieren von Images verwenden müssen. Reinen Docker-Basisimages fehlen normalerweise Tools wie wget, curl, git und gcc, die wir manuell installieren müssen.

Nehmen wir apt als Beispiel. Bei der Installation von Software kann apt-get eine Option angeben: --no-install-recommends . Nach Angabe dieses Parameters werden einige nicht unbedingt erforderliche Abhängigkeiten nicht zusammen installiert. Wenn wir beispielsweise bei der Installation von wget diese Option hinzufügen, wird die Anzahl der zu installierenden Pakete von 6 auf 3 reduziert:

Dadurch wird die Größe des Bildes bis zu einem gewissen Grad reduziert, der Nebeneffekt hierbei kann jedoch sein, dass der Zielsoftware einige Funktionen fehlen.

Beispielsweise kann wget an diesem Punkt die Echtheit des Serverzertifikats nicht überprüfen, was zu einem Befehlsfehler führt:

Daher besteht unsere allgemeine Vorgehensweise darin, bei der Verwendung von apt zu versuchen, --no-install-recommends hinzuzufügen und dann einige Fehler rechtzeitig zu korrigieren, wenn sie später auftreten. Bekannte Probleme wie wget können vorhergesagt und im Voraus behandelt werden:

apt-get install --no-install-recommends wget ca-Zertifikate

3. Räumen Sie das Chaos für apt auf

Einige Tools werden nur in der Kompilierungsphase verwendet. Ich möchte nicht, dass sie meine wertvolle Image-Kapazität beanspruchen. Ich kann diese Zwischenabhängigkeiten löschen, nachdem die Image-Kompilierung abgeschlossen ist.

Nehmen wir apt als Beispiel. Nachdem wir es verwendet haben, müssen wir Folgendes tun:

  • Entfernen Sie unnötige Abhängigkeiten: apt-get pruge --autoremove ...
  • Löschen Sie die lokale Paketliste: rm -rf /var/lib/apt/lists/*

Dabei stoßen wir auf ein sehr schwieriges Problem: Welche Abhängigkeiten sind „unnötig“?

Beispielsweise können wir beim Kompilieren von PHP drei Tools verwenden: wget, libxml und gcc. Diese drei Tools müssen vor der Kompilierung von PHP installiert werden. Aber nachdem die Kompilierung abgeschlossen ist, können wir wget und gcc deinstallieren, aber nicht libxml.

Der Grund dafür ist, dass libxml eine dynamische Linkbibliothek ist, von der PHP abhängt. Wenn wir sie deinstallieren, tritt ein Fehler auf, dass die gemeinsam genutzte Linkbibliothek nicht gefunden werden kann:

root@8eab53da8d5b:/# php -v
php: Fehler beim Laden gemeinsam genutzter Bibliotheken: libxml2.so.2: Gemeinsam genutzte Objektdatei kann nicht geöffnet werden: Keine solche Datei oder kein solches Verzeichnis

Gibt es für mich eine bequemere Möglichkeit, automatisch nur die Abhängigkeiten zu finden, die keine „Shared Link Libraries“ sind, und diese zu löschen?

Natürlich gibt es das. Eine einfachere Möglichkeit besteht darin, die neu kompilierte ausführbare Datei zu durchlaufen, den Befehl ldd zu verwenden, um die Namen der gemeinsam genutzten Linkbibliotheksdateien aufzulisten, von denen sie abhängt, und in der Quelle nach dem Paketnamen zu suchen, der diesem Dateinamen entspricht:

Diese Pakete sind alle dynamischen Linkbibliotheken, von denen PHP abhängt. Dann verwenden wir apt-mark , um diese Pakete als „manuell installierte Pakete“ zu deklarieren und zu verhindern, dass apt purge sie automatisch deinstalliert.

Anschließend können wir die verbleibenden, nicht verwendeten Pakete automatisch deinstallieren. Das vollständige Shell-Skript lautet wie folgt:

finde /usr/local -type f -executable -exec ldd '{}' ';' \
 | awk '/=>/ { print $(NF-1) }' \
 | sortieren -u \
 | xargs -r dpkg-query --search \
 | Schnitt -d: -f1 \
 | sortieren -u \
 | xargs -r apt-mark Handbuch \
; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false;

4. Versuchen Sie, Zwischenabhängigkeiten in einem Schritt zu installieren und zu deinstallieren

Ein Docker-Image ist ein mehrschichtiger Kuchen, der aus mehreren Schichten besteht. Mit docker history <image name> können wir sehen, aus welchen Schichten ein Image besteht und wie groß jede Schicht ist:

Bei Dockerfile werden die Daten dieser Ebenen im Image gespeichert, auch wenn die letztere Ebene die in der vorherigen Ebene gespeicherten Dateien löscht.

Beispielsweise haben wir das folgende Dockerfile:

VON alpin:3.12
RUN truncate -s 50M /sample.dat
Führen Sie den Befehl rm -rf /sample.dat aus.

Wir können versuchen herauszufinden, wie groß dieses kompilierte Bild ist: 58 MB:

Im Vergleich dazu ist die normale Datei „alpin:3.12“ nur 5,57 MB groß. Dies bedeutet, dass selbst wenn wir die Datei /sample.dat gelöscht haben, im endgültigen Bild kein derartiger Inhalt vorhanden ist, er aber immer im Bildverlauf verbleibt.

Daher müssen wir beim Löschen der oben genannten „Zwischenabhängigkeiten“ die drei Teile Installation, Verwendung und Deinstallation in einem Schritt schreiben, um sicherzustellen, dass der Speicherplatz freigegeben wird. Zum Beispiel:

VON debian:buster

Führen Sie apt-get update \ aus.
 && apt-get installiere gcc \
 && gcc … \
 && apt-get purge --autoremove gcc \
 && rm -rf /var/lib/apt/lists/*

5. Mehrstufige Kompilierung

Nach der Docker-Version 17.05 wurde das Konzept mehrstufiger Builds eingeführt, das alle unsere oben genannten Vorgänge erheblich vereinfachen wird.

Einfach ausgedrückt ermöglichen uns mehrstufige Builds, die Kompilierung von Docker-Images in mehrere „Phasen“ zu unterteilen. Beispielsweise können wir bei der Kompilierung allgemeiner Software die Kompilierungsphase trennen und die Binärdatei nach Abschluss der Softwarekompilierung direkt in ein neues Basisimage kopieren. Der größte Vorteil dabei besteht darin, dass das zweite Image keine in der Kompilierungsphase verwendeten Zwischenabhängigkeiten mehr enthält, was sauber und klar ist.

Am Beispiel des gängigsten Java-Projekts müssen wir beim Kompilieren des Jar-Pakets Tools wie JDK und Maven verwenden, in der eigentlichen Betriebsphase benötigen wir jedoch nur die JRE-Umgebung. Vergleichen wir die Größen der beiden Bilder: maven:3-openjdk-8 und openjdk:8-jre :

Der Unterschied beträgt mehr als das Doppelte.

Am Beispiel der Shiro 1.2.4-Umgebung in Vulhub sind in der Docker-Datei zwei FROM -Befehle zu sehen:

VON maven:3-jdk-8 ALS Builder

LABEL MAINTAINER="phithon <[email protected]>"

KOPIEREN ./code/ /usr/src/

ARBEITSVERZEICHNIS /usr/src

AUSFÜHREN cd /usr/src; \
 mvn -U sauberes Paket -Dmaven.test.skip=true

VON openjdk:8u102-jre

LABEL MAINTAINER="phithon <[email protected]>"

KOPIEREN --from=builder /usr/src/target/shirodemo-1.0-SNAPSHOT.jar /shirodemo-1.0-SNAPSHOT.jar

EXPOSE 8080

CMD ["java", "-jar", "/shirodemo-1.0-SNAPSHOT.jar"]

Das erste FROM wird verwendet, um maven:3-jdk-8 zu gelangen und Maven zum Kompilieren des Quellcodes zu verwenden; das zweite FROM gelangt in die kleinere Umgebung openjdk:8u102-jre und verwendet COPY --from= um die JAR-Datei aus dem Kompilierungsergebnis der vorherigen Phase in die JRE-Umgebung zu kopieren.

Schließlich verbleiben zwei Images auf der Maschine, eines ist der Builder und das andere die Shiro 1.2.4-Umgebung, die wir am Ende benötigen. Letzteres kann von jedem anderen Benutzer unabhängig verwendet werden, während Ersteres direkt gelöscht werden kann.

Für Benutzer bedeutet das, dass wir uns beim Kompilieren der Software keine Gedanken mehr darüber machen müssen, wie die Zwischenabhängigkeiten gelöscht werden, um das Image zu verkleinern. In der ersten Phase verwendete Abhängigkeiten verbleiben jedenfalls nicht in der formalen Produktionsumgebung.

Bei der mehrstufigen Kompilierung besteht jedoch immer noch das oben erwähnte Problem der Abhängigkeit von dynamischen Linkbibliotheken. Wenn wir beim Kopieren der Kompilierungsergebnisse nur die ausführbare Datei kopieren, tritt beim Ausführen in der neuen Umgebung immer noch der Fehler auf, dass die gemeinsam genutzte Linkbibliothek nicht gefunden wird. Daher bin ich persönlich der Meinung, dass die mehrstufige Kompilierung nur für Sprachen geeignet ist, die plattformübergreifend oder statisch kompiliert werden können, wie etwa Java und Golang, und immer noch nicht für Projekte mit mehr Abhängigkeiten wie etwa C und Python geeignet ist.

6. Verwenden Sie die schlanke Version des Bildes

Aufmerksamen Schülern ist möglicherweise aufgefallen, dass es vom offiziellen Docker-Debian-Image eine Slim-Version gibt, die mehr als doppelt so groß ist wie die Standardversion:

Die chinesische Bedeutung von Slim ist „schlank“. Wie der Name schon sagt, ist debian:stretch-slim tatsächlich viel schlanker, da es viele Dateien wie Man-Dokumente löscht, die im Container nicht verwendet werden.

Einige Images der höheren Ebene basieren auf der Slim-Version von Debian, beispielsweise Python. Wenn wir ein Python-Projekt entwickeln, können wir python:slim verwenden.

Zusammenfassend lässt sich sagen, dass die sechs Methoden sich gegenseitig nicht beeinflussen und wir sie gleichzeitig verwenden können. Aber fünftens wird die mehrstufige Kompilierung in Zukunft die gängige Methode sein.

Damit ist dieser Artikel über sechs Möglichkeiten zum Reduzieren der Größe von Docker-Images abgeschlossen. Weitere Informationen zum Reduzieren der Größe von Docker-Images finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Implementierung der Docker-Konfigurationsänderung des Alibaba Cloud-Image-Repository
  • Detaillierte Erklärung von 3 Möglichkeiten zum Erstellen von Docker-Images mit SpringBoot
  • Detaillierte Schritte für Springboot Docker Jenkins zum automatischen Bereitstellen und Hochladen von Bildern
  • So zeigen Sie Dateien im Docker-Image an
  • So bedienen Sie Docker und Images

<<:  Mysql NULL verursachte die Grube

>>:  JavaScript zum Erzielen von Spezialeffekten beim Treppenrollen (jQuery-Implementierung)

Artikel    

Artikel empfehlen

HTML verwendet Laufschrift, um Text nach links und rechts scrollen zu lassen

Code kopieren Der Code lautet wie folgt: <KÖRP...

Detaillierte Erklärung des Typschutzes in TypeScript

Inhaltsverzeichnis Überblick Typzusicherungen in ...

Einführung in lokale Komponenten in Vue

In Vue können wir lokale Komponenten selbst defin...

MySQL Series 6-Benutzer und Autorisierung

Inhaltsverzeichnis Tutorial-Reihe 1. Benutzerverw...

CSS3 Flexible Box Flex, um ein dreispaltiges Layout zu erreichen

Wie der Titel schon sagt: Die Höhe ist bekannt, d...

So lernen Sie algorithmische Komplexität mit JavaScript

Inhaltsverzeichnis Überblick Was ist die O-Notati...

Beispielcode eines CSS-responsiven Layoutsystems

Responsive Layoutsysteme sind in den heute gängig...

Implementierung des WeChat-Applet-Nachrichten-Pushs in Nodejs

Auswählen oder Erstellen einer Abonnementnachrich...

Tipps zum Schreiben prägnanter React-Komponenten

Inhaltsverzeichnis Vermeiden Sie die Verwendung d...

HTML implementiert problemlos abgerundete Rechtecke

Frage: Wie erreiche ich mit Div+CSS und Positioni...