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.
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.
Eine Vereinfachung des Containerbildes ist sehr wichtig. Wir werden darüber sowohl in Bezug auf Sicherheit als auch in Bezug auf Agilität sprechen.
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.
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.
Führen Sie die folgenden Schritte aus, um Ihre Java-Anwendung zu containerisieren:
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.
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.
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.
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.
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.
Zusätzlich zu den oben genannten Tipps können Sie die Bildgröße weiter vereinfachen, indem Sie die folgenden Vorgänge ausführen.
Recommended Posts