[DOCKER] So minimieren Sie Java-Images

In diesem Artikel wird eine ** Spring Boot ** -basierte ** Java ** -Anwendung als Beispiel verwendet, um Ihnen einige allgemeine Tipps zum Minimieren von ** Java ** -Bildern zu geben.

Hintergrund

Mit der Verbreitung der Containertechnologie nehmen die Anwendungen auf Containerbasis zu. Obwohl Container häufig verwendet werden, ignorieren die meisten Containerbenutzer möglicherweise das einfache, aber wichtige Problem der Containerbildgröße. Dieser Artikel beschreibt kurz die Notwendigkeit, Container-Images zu vereinfachen, und stellt einige gängige Tricks zur Minimierung von Java-Images am Beispiel von Spring Boot-basierten Java-Anwendungen vor.

Container-Image muss vereinfacht werden

Eine Vereinfachung des Containerbildes ist sehr wichtig. Wir werden darüber sowohl in Bezug auf Sicherheit als auch in Bezug auf Agilität sprechen.

Über Sicherheit

Durch Entfernen unnötiger Komponenten aus dem Image können Sie die Angriffsfläche und das Sicherheitsrisiko verringern. In Docker können Sie Seccomp verwenden, um Vorgänge innerhalb des Containers einzuschränken, oder App Armor verwenden. Sie können auch //docs.docker.com/engine/security/apparmor/?spm=a2c65.11461447.0.0.4c817eccQzbPjk) verwenden, um die Sicherheitsrichtlinie für Ihren Container festzulegen. Sie müssen jedoch die Sicherheitskenntnisse beherrschen, um sie verwenden zu können.

Beweglichkeit

Durch Vereinfachung des Container-Images können Sie die Bereitstellung des Containers beschleunigen. Angenommen, Sie haben einen plötzlichen Ausbruch des Zugangsverkehrs und müssen die Anzahl der Container erhöhen, um den plötzlichen Druckanstieg zu bewältigen. Wenn einige Hosts das Ziel-Image nicht enthalten, müssen Sie zuerst das Image ziehen und dann den Container starten. In diesem Fall können Sie den Vorgang beschleunigen und die Skalierungszeit verkürzen, indem Sie das Bild verkleinern. Außerdem können kleinere Bilder schneller erstellt werden, wodurch Speicher- und Übertragungskosten gespart werden.

Allgemeine Tipps

Führen Sie die folgenden Schritte aus, um Ihre Java-Anwendung zu containerisieren:

  1. Kompilieren Sie den Java-Quellcode und generieren Sie ein JAR-Paket.
  2. Verschieben Sie das JAR-Paket und die JAR-Abhängigkeiten von Drittanbietern an den entsprechenden Speicherort. Das in diesem Abschnitt verwendete Beispiel ist eine Spring Boot-basierte Java-Anwendung Spring-Boot-Docker ) ist. Die in diesem Beispiel verwendete nicht optimierte Docker-Datei lautet:
FROM maven:3.5-jdk-8
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package
ENTRYPOINT ["java","-jar","/usr/src/app/target/spring-boot-docker-1.0.0.jar"]

Die Anwendung wurde mit Maven erstellt, und maven: 3.5.5-jdk-8 wird als Basisimage der Docker-Datei angegeben. Die Größe dieses Bildes beträgt 635 MB. Die Größe des mit dieser Methode erstellten endgültigen Bildes ist mit 719 MB recht groß. Der Grund ist, dass das Basis-Image groß ist und Maven viele JAR-Pakete herunterlädt, um das endgültige Image zu erstellen.

Mehrstufiger Aufbau

Zum Ausführen von Java-Anwendungen ist nur die Java Runtime Environment (JRE) erforderlich. Es sind keine Kompilierungs-, Debugging- oder Ausführungstools für Maven oder Java Development Kit (JDK) erforderlich. Daher besteht eine einfache Optimierungsmethode darin, das durch Kompilieren des Java-Quellcodes erstellte Image von dem Image zu trennen, auf dem die Java-Anwendung ausgeführt wird. Zu diesem Zweck müssen Sie vor der Veröffentlichung von Docker 17.05 zwei Dockerfile-Dateien verwalten, was die Komplexität beim Erstellen des Images erhöht. Ab Docker 17.05 mehrere in einer Docker-Datei mit der Funktion Multistage Build Sie können jetzt die FROM-Anweisung von verwenden. Sie können für jede FROM-Anweisung ein anderes Basis-Image angeben und einen völlig neuen Image-Erstellungsprozess starten. Sie können das Produkt aus der vorherigen Phase der Image-Erstellung in eine andere Phase kopieren und nur das, was Sie benötigen, im endgültigen Image belassen. Die optimierte Docker-Datei befindet sich unten Es wird so sein.

FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package

FROM openjdk:8-jre
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

Die Docker-Datei verwendet maven: 3.5-jdk-8 als Build-Image für die erste Stufe und openjdk: 8-jre als Basis-Image für die Ausführung von Java-Anwendungen. Nur die in der ersten Stufe kompilierte ".class" -Datei wird zusammen mit den Abhängigkeiten der JAR eines Drittanbieters in das endgültige Image kopiert. Durch die Optimierung wurde die Bildgröße auf 459 MB reduziert.

Verwenden Sie ein verzweifeltes Bild als Basisbild

Das endgültige Bild ist aufgrund des mehrstufigen Builds kleiner, aber 459 MB sind immer noch zu groß. Als Ergebnis einer umfassenden Analyse wurde festgestellt, dass die Größe der Basis "openjdk: 8-jre" mit 443 MB zu groß ist. Daher haben wir uns als nächsten Optimierungsschritt entschlossen, die Größe des Basisbilds zu reduzieren.

Das Open Source-Projekt [Distroless] von Google (https://github.com/GoogleContainerTools/distroless?spm=a2c65.11461447.0.0.4c817eccQzbPjk) wurde entwickelt, um dieses Problem zu lösen. Das Distroless-Image enthält nur die Anwendung und ihre Laufzeitabhängigkeiten. Diese Images enthalten weder Package Manager, Shell noch ein anderes Programm, das Sie von einer Standard-Linux-Distribution erwarten würden. Derzeit ist Distroless Java, [Python](https :: //github.com/GoogleContainerTools/distroless/blob/master/experimental/python2.7/README.md?spm=a2c65.11461447.0.0.4c817eccQzbPjk&file=README.md), [Node.js](https: // github. de / GoogleContainerTools / Distroless / Blob / Master / Experimental / NodeJS / README.md? spm = a2c65.11461447.0.0.4c817eccQzbPjk & file = README.md), .NET /master/experimental/dotnet/README.md?spm=a2c65.11461447.0.0.4c817eccQzbPjk&file=README.md) Bietet ein Basisimage für Anwendungen, die in Umgebungen wie z.

Die Datei dockerfile, die das Distroless-Image verwendet, lautet wie folgt Es wird so sein.

FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package

FROM gcr.io/distroless/java
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

Der einzige Unterschied zwischen dieser Docker-Datei und der vorherigen besteht darin, dass das Basis-Image zum Ausführen der Anwendung von "openjdk: 8-jre" (443 MB) in "gcr.io / Distroless / Java" (119 MB) geändert wurde. Das ist. Das Ergebnis ist eine endgültige Bildgröße von 135 MB.

Die einzige Unannehmlichkeit bei der Verwendung eines verzweifelten Bildes besteht darin, dass das Bild keine Shell enthält. Sie können Docker Attach nicht verwenden, um Standardeingaben, Standardausgaben und Standardfehler (oder Kombinationen dieser drei) Ihrer Anwendung an einen laufenden Container anzuhängen und zu debuggen. Das Distroless Debug-Image bietet eine Busybox-Shell. Ich muss dieses Image jedoch neu packen und den Container bereitstellen, was für Container, die basierend auf Nicht-Debug-Images bereitgestellt werden, nicht hilfreich ist. Aus Sicherheitsgründen kann dies ein Vorteil sein, da ein Angreifer nicht über die Shell angreifen kann.

Verwenden Sie ein Alpenbild als Basisbild

Wenn Sie Docker Attach verwenden müssen und die Bildgröße minimieren möchten, können Sie ein Alpenbild als Basisbild verwenden. Alpine Das Bild ist unglaublich klein und die Größe des Basisbilds beträgt nur etwa 4 MB.

Dockerfile mit alpinen Bildern lautet wie folgt Wird sein.

FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package

FROM openjdk:8-jre-alpine
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

openjdk: 8-jre-alpine basiert auf alpine und enthält die Java-Laufzeit. Die Größe des mit dieser Docker-Datei erstellten Bildes beträgt 99,2 MB, was kleiner ist als das Bild, das basierend auf dem verzweifelten Bild erstellt wurde.

Führen Sie zum Anhängen an einen laufenden Container den Befehl docker exec -ti <container_id> sh aus.

Vergleich von Distroless und Alpine

Sowohl Distroless als auch Alpine können sehr kleine Basisbilder liefern. Welches sollte ich in einer Produktionsumgebung verwenden? Wenn Sicherheit oberste Priorität hat, wird Distroless empfohlen, da gepackte Anwendungen nur Binärdateien ausführen können. Wenn Sie die Größe des Bildes schätzen, empfehlen wir alpine.

Andere Tipps

Zusätzlich zu den oben genannten Tipps können Sie die Bildgröße weiter vereinfachen, indem Sie die folgenden Vorgänge ausführen.

  1. Kombinieren Sie mehrere Anweisungen in der Docker-Datei zu einer. Dies reduziert die Anzahl der Ebenen im Bild und die Bildgröße.
  2. Platzieren Sie großen, stabilen Inhalt unten im Bild und kleinen, häufig wechselnden Inhalt oben. Mit dieser Methode können Sie die Bildgröße nicht direkt reduzieren. Der Image-Cache-Mechanismus wird jedoch voll genutzt, um die Image-Erstellung und die Container-Bereitstellung zu beschleunigen. Tipps zum Optimieren von Docker-Dateien finden Sie unter Best Practices zum Schreiben von Docker-Dateien (https://docs.docker.com/develop/develop-images/dockerfile_best-practices/?spm=a2c65.11461447.0.0.4c817eccQzbPjk) )Bitte beziehen Sie sich auf.

Überblick

  1. Durch eine Reihe von Optimierungen wurde die Bildgröße von Java-Anwendungen von 719 MB auf etwa 100 MB reduziert. Wenn Ihre Anwendung in anderen Umgebungen ausgeführt wird, können Sie sie auf ähnlicher Basis optimieren.
  2. Für Java-Images automatisiert ein anderes von Google bereitgestelltes Tool, jib, den komplexen Image-Erstellungsprozess. Kann verarbeitet und ein vereinfachtes Java-Image bereitgestellt werden. Damit müssen Sie keine Docker-Datei schreiben oder Docker installieren.
  3. Wenn Sie das Protokoll für Container wie distro-less, die für das Debuggen unpraktisch sind, zentral speichern, ist es einfacher, Probleme zu verfolgen und zu beheben. Weitere Informationen finden Sie im Artikel Technische Best Practices für die Containerprotokollierung.

Recommended Posts

So minimieren Sie Java-Images
[Schienen] Wie poste ich Bilder?
So senken Sie die Java-Version
[Java] Verwendung von Map
So deinstallieren Sie Java 8 (Mac)
Java - So erstellen Sie JTable
Umgang mit hochgeladenen Bildern
Wie schreibe ich einen Java-Kommentar
Verwendung der Java-Klasse
[Java] Verwendung von removeAll ()
[Java] So zeigen Sie Wingdings an
Verwendung von Java Map
So legen Sie Java-Konstanten fest
Verwendung von Java-Variablen
So konvertieren Sie Java Base
[Java] So implementieren Sie Multithreading
So initialisieren Sie ein Java-Array
So lernen Sie Java Silver SE 8
Verwendung von HttpClient (Get) von Java
Java # 6 studieren (Wie man Blöcke schreibt)
So erstellen Sie einen Java-Container
So zerlegen Sie eine Java-Klassendatei
Verwendung von HttpClient (Post) von Java
[Java] Verwendung der Join-Methode
Wie man JAVA in 7 Tagen lernt
[Verarbeitung × Java] Verwendung von Variablen
So dekompilieren Sie eine Java-Klassendatei
[JavaFX] [Java8] Verwendung von GridPane
So schreiben Sie eine Java-Variablendeklaration
Verwendung von Klassenmethoden [Java]
[Java] Verwendung von List [ArrayList]
Wie verwende ich Klassen in Java?
So benennen Sie Variablen in Java
So übergeben Sie Oracle Java Silver
So drehen Sie Iterator Dojo (Java)
Java Eclips So debuggen Sie JavaScript
[Verarbeitung × Java] Verwendung von Arrays
So erstellen Sie ein Java-Array
Verwendung von Java-Lambda-Ausdrücken
[Java] Verwendung der Math-Klasse
So finden Sie Java-Primzahlen
Verwendung des Java-Aufzählungstyps
So verketten Sie Zeichenfolgen mit Java
So erstellen Sie eine Java-Kalenderzusammenfassung
So implementieren Sie die Datumsberechnung in Java
So implementieren Sie den Kalman-Filter mit Java
Mehrsprachige Unterstützung für Java Verwendung des Gebietsschemas
So kompilieren Sie Java mit VsCode & Ant
[Rails] So laden Sie Bilder mit Carrierwave hoch
[Java] Hinzufügen von Daten zur Liste (add, addAll)
So wechseln Sie Miniaturbilder mit JavaScript
[Java] So berechnen Sie das Alter mit LocalDate
So führen Sie eine Basiskonvertierung in Java durch