Mit JLink kleinere Docker-Images für Ihre Spring-Boot-Java-Anwendung erstellen
24. August 2023
0 Min. LesezeitContainer bieten neue Flexibilität und Agilität bei der Softwareentwicklung und -bereitstellung. Sie schaffen jedoch auch eine neue Angriffsfläche, die sich böswillige Akteure zunutze machen können. Ein kompromittierter Container kann Angreifern Zugriff auf andere Container und sogar auf das Hostsystem verschaffen. Kleinere Images mit weniger Artefakten tragen bereits wesentlich dazu bei, die Angriffsfläche zu verringern.
In diesem Blogbeitrag zeigen wir ausführlich, wie Sie mit JLink die Größe von Docker-Images optimieren und so die Anwendungssicherheit und -leistung verbessern. Wir zeigen Ihnen, wie Sie JLink verwenden und in Docker integrieren, um Ihre Spring-Boot- oder allgemeinen Java-Anwendungen effizient bereitzustellen.
Einführung in JLink
Java gehört weltweit zu den am häufigsten verwendeten Programmiersprachen für die Entwicklung von Unternehmensanwendungen. Bei der Bereitstellung von Java-Anwendungen in Docker-Containern haben Entwickler jedoch oft mit der Größe der Docker-Images zu kämpfen. Eine Möglichkeit, dieses Problem zu lösen, ist die Verwendung von JLink, einem mit JDK 9 eingeführten Tool.
JLink (Java Linker) ist ein Befehlszeilentool, das eine Gruppe von Modulen samt Abhängigkeiten zu einem benutzerdefinierten Runtime-Image zusammenstellt und optimiert. Im Wesentlichen erstellt es eine minimale Java-Runtime-Umgebung, die nur die für Ihre Anwendung erforderlichen Module enthält.
Im obigen Befehl steht my.module für Ihr Modul und myRuntime für das benutzerdefinierte Runtime-Image, das JLink erstellt.
Die Rolle von JLink beim Erstellen kleinerer Docker-Images
Beim Erstellen von Docker-Images für Java-Anwendungen ist die Image-Größe oft ein wichtiger Faktor – insbesondere bei Spring-Boot-Anwendungen, die viele Abhängigkeiten mitbringen. Ein großes Docker-Image kann zu längeren Startzeiten, höheren Speicherkosten und langsameren Bereitstellungsprozessen führen.
Bei älteren Java-Versionen war im Java Development Kit (JDK) eine Java Runtime Environment (JRE) enthalten. Zum Ausführen des erstellten Java-Artefakts war nur die JRE erforderlich. Daher war es früher üblich, die JRE im Docker-Image zu verwenden oder ein JRE-Basis-Image für Container auszuwählen. Neuere Java-Versionen enthalten nicht immer eine JRE, auch wenn einige Anbieter weiterhin eine JRE und entsprechende Basis-Images bereitstellen. Sie können diese oder eine speziell auf Ihre Anwendung zugeschnittene Java-Runtime verwenden.
Mit JLink können Sie eine minimale Java-Runtime erstellen, die nur die erforderlichen Module enthält. Dadurch lässt sich die Größe Ihres Docker-Images deutlich reduzieren. Eine Standard-Java-Runtime-Umgebung kann beispielsweise mehr als 200 MB groß sein. Mit JLink können Sie sie auf weniger als 50 MB verkleinern.
JLink für eine Spring-Boot-Java-Anwendung verwenden
Spring Boot erstellt für Ihre Anwendungen ein Fat JAR, das alle Abhängigkeiten enthält. Außerdem verfügen viele Spring-Boot-Anwendungen über keine Moduldeklaration. Das muss kein Problem sein, aber wir müssen ermitteln, welche Module die Anwendung und all ihre Abhängigkeiten benötigen.
Mit Jdeps das Modul ermitteln
Jdeps ist ein Java-Tool, das Abhängigkeiten auf Paket- oder Klassenebene anzeigt. Mit dem in Java 8 eingeführten Tool lassen sich die Abhängigkeiten einer Anwendung ermitteln. Diese Informationen können anschließend dazu verwendet werden, mit JLink ein benutzerdefiniertes Runtime-Image zu erstellen.
Wenn sichergestellt ist, dass sich alle Abhängigkeiten in einem Verzeichnis befinden, können wir mit jdeps eine Zusammenfassung der Abhängigkeiten ausgeben.
Ebenso können wir mit jdeps rekursiv alle Modulabhängigkeiten der Spring-Boot-Anwendung und ihrer Abhängigkeiten ausgeben.
Die von jdeps generierte Ausgabe ermöglicht es JLink, eine Java-Runtime zu erstellen, die nur die für diese Spring-Boot-Anwendung benötigten Module enthält.
Spring-Boot-Abhängigkeiten in einen Ordner ausgeben
Wie erwähnt, erstellt Spring Boot ein Fat JAR, das alle Abhängigkeiten enthält. Die Abhängigkeiten sind im JAR jedoch auf eine bestimmte Weise gepackt und daher für jdeps nicht leicht zugänglich. Es gibt zwei einfache Möglichkeiten, die Abhängigkeiten für jdeps verfügbar zu machen.
Das von Spring Boot erstellte Fat JAR entpacken.
Diese Option eignet sich hervorragend, wenn das Build-Artefakt bereits erstellt wurde und Sie die Anwendung nicht neu erstellen möchten oder können. Die Abhängigkeiten werden nach
/BOOT/libs/entpackt.
Ein Plugin in Ihrem Build-Tool verwenden, das die Abhängigkeiten in einen bestimmten Ordner kopiert.
In Maven lässt sich dies beispielsweise mit dem
maven-dependency-pluginerreichen. Im folgenden Beispiel werden die Abhängigkeiten nach Abschluss der Maven-Package-Phase in den Ordner/target/dependencykopiert.
Ein Docker-Image mit einer benutzerdefinierten Java-Runtime erstellen
Kombinieren wir nun jdeps und JLink, um eine benutzerdefinierte Java-Runtime zu erstellen. Damit können wir ein optimales, minimales Docker-Image speziell für eine Spring-Boot-Anwendung erstellen.
Im obigen Beispiel habe ich einen mehrstufigen Docker-Build verwendet. Die erste Build-Stufe basiert auf einem eclipse-temurin-JDK-17-Image mit Maven. Diese Stufe dient dazu:
Das Java-Artefakt zu erstellen. Mit Maven erstelle ich das ausführbare Fat JAR, das die gesamte Anwendung enthält.
Das JAR zu entpacken, damit alle Abhängigkeiten verfügbar sind. Das ist nur erforderlich, wenn Sie nicht wie zuvor beschrieben das
maven-dependency-pluginverwenden. Wenn Sie es eingebunden haben, können Sie diesen Schritt überspringen.Mit jdeps die erforderlichen Module ermitteln. Geben Sie den Pfad zur Datei mit allen Abhängigkeits-JAR-Dateien und zum endgültigen Artefakt an und speichern Sie die Liste in
deps.info.JLink ausführen, um eine benutzerdefinierte Java-Runtime zu erstellen. Verwenden Sie
deps.infoals Eingabe und speichern Sie das Ergebnis unter/myjre. Wir fügen nur die für JLink erforderlichen Module hinzu und entfernen Debug-Informationen, Handbuchseiten und Header-Dateien.
Die zweite und letzte Stufe erstellt das Produktions-Image auf Grundlage eines debian:stable-slim-Images.
Umgebungsvariablen festlegen. Legen Sie
JAVA_HOMEauf den Pfad fest, in den ichmyjrekopiere, und fügen SieJAVA_HOMEzuPATHhinzu.Die mit JLink erstellte Java-Runtime kopieren. Verweisen Sie auf die erste Stufe und kopieren Sie die benutzerdefinierte Java-Runtime an den als
JAVA_HOMEdefinierten Speicherort.Das erstellte Java-Artefakt kopieren. Das erstellte ausführbare Spring-Boot-Fat-JAR wird in das dafür vorgesehene Projektverzeichnis kopiert.
Entrypoint festlegen
JLink bietet beim Erstellen von Docker-Images für Spring-Boot-Java-Anwendungen mehrere Vorteile:
1. Geringere Image-Größe: Wie bereits erwähnt, kann JLink die Größe Ihres Docker-Images verringern. Das führt zu schnelleren Bereitstellungen und niedrigeren Speicherkosten.
2. Kürzere Startzeiten: Ein kleineres Docker-Image bedeutet, dass Ihre Anwendung schneller gestartet werden kann. Das ist entscheidend für Anwendungen, die schnell skaliert werden müssen.
3. Sicherheit: Wenn Sie nur die erforderlichen Module einbinden, verringern Sie die Angriffsfläche Ihrer Anwendung. Weniger Module bedeuten weniger potenzielle Sicherheitslücken.
Apropos Sicherheit: Die Rolle von Snyk beim Schutz Ihrer Anwendungen sollte nicht unerwähnt bleiben. Snyk ist ein Developer-Security-Tool, das Ihren Quellcode, Open-Source-Pakete, Container-Images und Cloud-Konfigurationen auf Sicherheitslücken prüfen kann. Mit Snyk Container und Snyk Open Source können Sie Sicherheitsprobleme in Ihrer Anwendung und deren Abhängigkeiten erkennen und beheben – auch in Ihren Docker-Images.
Im obigen Befehl steht your-repo/your-image:tag für Ihr Docker-Image. Snyk scannt es und meldet erkannte Sicherheitslücken sowie Vorschläge zu deren Behebung.
Kleinere und sicherere Docker-Images für Java-Anwendungen erstellen
Beachten Sie, dass die Beispiele in diesem Blogbeitrag zeigen sollen, wie Sie mit JLink ein kompakteres Docker-Image für Ihre Java-Projekte erstellen. Sie erfüllen nicht alle Best Practices für sichere Docker-Images. Weitere Informationen finden Sie in unserem Artikel „10 Best Practices zum Erstellen eines Java-Containers mit Docker“, der Ihnen als Inspiration dienen kann.
Zusammenfassend lässt sich sagen: JLink ist ein leistungsstarkes Tool, mit dem Sie kleinere und sicherere Docker-Images für Ihre Spring-Boot-Java-Anwendungen erstellen können. In Kombination mit Sicherheitstools wie Snyk können Sie sicherstellen, dass Ihre Anwendungen leistungsfähig und sicher sind. Worauf warten Sie noch? Registrieren Sie sich noch heute bei Snyk und schützen Sie Ihre Anwendungen.
Container-Sicherheit mit Fokus auf Entwickler
Snyk findet und behebt automatisch Schwachstellen in Container-Images und Kubernetes-Workloads.
