Containerisieren einer Java-App
In dieser Einheit containern Sie eine Java-Anwendung.
Wie bereits erwähnt, werden Container direkt über dem Hostbetriebssystem, Kernel und Hardware als gewöhnliche Systemprozesse ausgeführt. Container benötigen weniger Systemressourcen, was zu einem geringeren Speicherbedarf, weniger Aufwand und schnelleren Startzeiten der Anwendung führt. Diese Vorteile sind großartige Anwendungsfälle für die Skalierung bei Bedarf.
Es gibt Windows-Container und Linux-Container. In diesem Modul verwenden Sie die weit verbreitete Docker-Laufzeit, um ein Linux-Containerimage zu erstellen. Anschließend stellen Sie das Linux-Containerimage auf dem Hostbetriebssystem Ihres lokalen Computers bereit. Schließlich stellen Sie das Linux-Containerimage für Azure Kubernetes Service bereit.
Docker-Übersicht
Die Docker-Laufzeit wird zum Erstellen, Abrufen, Ausführen und Pushen von Container-Images verwendet, wie im folgenden Diagramm dargestellt.
In der folgenden Tabelle werden die einzelnen Docker-Befehle beschrieben:
| Docker-Befehl | BESCHREIBUNG |
|---|---|
docker build |
Erstellt ein Containerimage, das aus den Anweisungen oder Ebenen besteht, die für Docker erforderlich sind, um einen ausgeführten Container aus einem Image zu erstellen. Das Ergebnis dieses Befehls ist ein Bild. |
docker pull |
Lädt ein Image aus einer Registrierung in den Imagespeicher des vom Client ausgewählten Docker-Daemons herunter. Vorhandene Bildebenen können wiederverwendet werden. In diesem Modul verwendet Ihre lokale Docker-Umgebung während der Entwicklung Images aus Registrys; später rufen AKS-Knoten das Anwendungsimage aus Azure Container Registry für die Bereitstellung ab. |
docker run |
Erstellt und startet einen neuen Container aus einem Image. Der Container führt seinen konfigurierten Startprozess aus, vorbehaltlich von Befehlszeilenüberschreibungen. Imageebenen stellen das Dateisystem des Containers bereit; Dockerfile-Buildanweisungen werden beim Starten des Containers nicht erneut ausgeführt. |
docker push |
Die Azure Container Registry speichert die Images, sodass sie für Azure-Bereitstellungen leicht verfügbar und für Skalierungsvorgänge netzwerknah sind. |
Klonen der Java-Anwendung
Klonen Sie zuerst das Repository des Flugbuchungssystems für Flugreservierungen und navigieren Sie zum Projektordner der Webanwendung Fluggesellschaften.
Hinweis
Wenn die Erstellung des Azure Kubernetes-Diensts auf ihrer CLI-Registerkarte abgeschlossen ist, verwenden Sie diese Registerkarte. Wenn sie noch ausgeführt wird, öffnen Sie eine neue Registerkarte, und navigieren Sie zu dem Ort, an dem Sie das Flugbuchungssystem für Flugreservierungen klonen möchten.
Führen Sie die folgenden Befehle aus:
git clone https://github.com/Azure-Samples/containerize-and-deploy-Java-app-to-Azure.git
cd containerize-and-deploy-Java-app-to-Azure/Project/Airlines
Wenn Sie Java und Maven installiert haben, können Sie optional den folgenden Befehl in Ihrer Terminalkonsole ausführen, um ein Gefühl der Erfahrung beim Erstellen der Anwendung ohne Docker zu erhalten. Wenn Sie Java und Maven nicht installiert haben, können Sie sicher mit dem nächsten Abschnitt fortfahren, erstellen Sie eine Docker-Datei. In diesem Abschnitt verwenden Sie Docker, um Java und Maven herunterzuziehen, um die Builds in Ihrem Auftrag auszuführen.
mvn clean package
Hinweis
Wir haben den mvn clean package-Befehl verwendet, um die betrieblichen Herausforderungen bei der Nichtverwendung von Docker-Multistage-Builds zu veranschaulichen, die wir als Nächstes behandeln. Auch hier ist dieser Schritt optional. Auf beide Weise können Sie sicher fortfahren, ohne den Maven-Befehl auszuführen.
Wenn der Prozess erfolgreich war, baute Maven erfolgreich das Flight Booking System für Airline Reservations Web Application Archive-Artefakt AirlinesReservationSample-0.0.1-SNAPSHOT.war, wie in der folgenden historischen Ausgabe dargestellt. Ihr Buildzeitstempel und die Dauer können variieren:
[INFO] Building war: $PROJECT_PATH/containerize-and-deploy-Java-app-to-Azure/Project/Airlines/target/AirlinesReservationSample-0.0.1-SNAPSHOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.776 s
[INFO] Finished at: 2024-11-15T09:33:26+09:00
[INFO] ------------------------------------------------------------------------
Stellen Sie sich vor, Sie sind Java-Entwickler und haben soeben AirlinesReservationSample-0.0.1-SNAPSHOT.war erstellt. Ihr nächster Schritt besteht wahrscheinlich darin, mit den Betriebstechnikern zusammenzuarbeiten, um dieses Artefakt entweder auf einem lokalen Server oder einem virtuellen Computer bereitgestellt zu bekommen. Damit die Anwendung erfolgreich gestartet und ausgeführt werden kann, müssen die Server und virtuellen Computer mit den erforderlichen Abhängigkeiten verfügbar und konfiguriert sein. Dieser Prozess ist schwierig und zeitaufwändig, insbesondere bei Bedarf, wenn eine erhöhte Last auf Ihre Anwendung trifft. Mit Containern werden diese Herausforderungen gemildert.
Erstellen einer Dockerfile-Datei
Sie können jetzt eine Dockerfile-Datei erstellen. Eine Dockerfile ist ein Textdokument, das alle Befehle enthält, die ein Benutzer in der Befehlszeile ausführen würde, um ein Containerimage zusammenzustellen. Ein Containerimage kann mehrere schreibgeschützte Dateisystemebenen enthalten. Docker kann zwischengespeicherte Buildergebnisse für unveränderte Schritte wiederverwenden. Die Ebenen bauen aufeinander auf.
Beispielsweise muss das Flugbuchungssystem für Flugreservierungen innerhalb eines Anwendungsservers bereitgestellt und ausgeführt werden. Ein Anwendungsserver wird nicht innerhalb des AirlinesReservationSample-0.0.1-SNAPSHOT.war verpackt. Es handelt sich um eine externe Abhängigkeit, die für die Ausführung von AirlinesReservationSample-0.0.1-SNAPSHOT.war erforderlich ist, um HTTP-Anforderungen zu überwachen und zu verarbeiten, Benutzersitzungen zu verwalten und Flight-Buchungen zu erleichtern. Wenn Sie eine herkömmliche, nicht containerisierte Bereitstellung verwendet haben, würden Betriebstechniker einen Anwendungsserver auf einem physischen Server oder virtuellen Computer installieren und konfigurieren, bevor Sie die AirlinesReservationSample-0.0.1-SNAPSHOT.war für sie bereitstellen. Diese Betriebsingenieure müssten auch sicherstellen, dass das JDK, das auf Ihrem Computer verwendet wird - was mvn clean package zum Kompilieren der WAR-Datei verwendet wird - tatsächlich demselben JRE entspricht, der vom Anwendungsserver verwendet wird. Die Verwaltung dieser Abhängigkeiten ist schwierig und zeitaufwändig.
Mit einem Dockerfile können Sie die Anweisungen oder Schichten schreiben, die erforderlich sind, um dieses Ziel automatisch zu erreichen. Dabei schichten Sie die Schritte aufeinander, die erforderlich sind, um sicherzustellen, dass das Flugbuchungssystem für Flugreservierungen alle Abhängigkeiten aufweist, die für die Bereitstellung in der Docker-Container-Runtime benötigt werden. Diese Lösung ist überzeugend, wenn Sie mit bedarfsorientierter Skalierung in ungeplanten Intervallen umgehen. Jede Ebene verwendet Docker-Cache, der den Status des Containerimages an jedem Anweisungsmeilenstein enthält, wodurch die Berechnungszeit optimiert und wiederverwendet wird. Wenn sich eine Ebene nicht ändert, werden zwischengespeicherte Ebenen verwendet. Häufige Anwendungsfälle für zwischengespeicherte Ebenen sind die Java-Runtime, der Anwendungsserver und andere Abhängigkeiten für das Flight Booking System für airline Reservations-Webanwendung. Wenn und wenn sich eine Version auf einer zuvor zwischengespeicherten Ebene ändert, wird ein neuer zwischengespeicherter Eintrag erstellt.
Ein Containerimage enthält schreibgeschützte Dateisystemebenen. In diesem Beispiel kopiert die Dockerfile Tomcat und die Flight Booking System WAR-Datei zur Erstellungszeit in das Image. Docker fügt eine separate schreibbare Ebene hinzu, wenn ein Container aus dem Image erstellt wird. Die beschreibbare Ebene jedes Containers zeichnet ihre eigenen Dateisystemänderungen auf, ohne die Imageebenen zu ändern.
Hinweis
Bei Dateien, die auf der beschreibbaren Ebene des Containers gespeichert sind, wirken sich Ergänzungen, Änderungen und Löschungen auf diesen Container und nicht auf das ursprüngliche Image aus. Das Ändern von Dateien, die von einer Bildebene stammen, erfolgt mit Copy-on-Write-Verhalten.
Docker verfügt über das Konzept von Multistage-Builds, einem Feature, mit dem Sie ein kleineres Containerimage mit besserer Zwischenspeicherung und einem kleineren Sicherheitsbedarf erstellen können, was eine höhere Optimierung und Wartung der Dockerfile im Laufe der Zeit ermöglicht. Sie können z. B. die Containerbuildphase zum Kompilieren und Erstellen der Anwendung von der Phase zum Ausführen der Anwendung trennen. Mit diesem Feature können Sie nur die Während des Builds generierten Artefakte in das Produktionscontainerimage kopieren, wodurch der Speicherbedarf reduziert wird. Da Containerimages zwischengespeichert werden, wenn keine Änderungen vorhanden sind, können die zwischengespeicherten Images wiederverwendet werden, wodurch die Kosten und die Zeit für den Download aus dem Netzwerk reduziert werden.
Dienste, die in der Produktionsumgebung verfügbar gemacht werden, müssen für die Sicherheit sorgfältig verwaltet werden. Daher verwendet und betreibt die Produktionsumgebung ein sicheres Containerimage. Im Beispiel wird ein Azure Linux-Image verwendet, das von Microsoft bereitgestellt wird.
Die letzte Phase verwendet Microsoft-Build von OpenJDK 17 auf Azure Linux 3.0. Das 17-azurelinux Tag benennt diese Basis explizit. Das ältere 17-mariner Tag bleibt ein Kompatibilitätsalias, der das Azure Linux-Image widerspiegelt. Es sollte nicht mit den eingestellten 17-mariner-cm1 und 17-mariner-cm2 Images verwechselt werden. Weitere Informationen finden Sie unter Microsoft-Build von OpenJDK Containerimages.
Hinweis
Microsoft bietet Containerimages, die mit OpenJDK gebündelt sind, einschließlich Ubuntu, Azure Linux und distroless Images. Das distroless Bild hat die kleinste Bildgröße, aber das Ausführen von Tomcat ist eine Herausforderung. Um ein einfaches Design zu erzielen, entfernt das distroless Bild viele Befehle und Tools, einschließlich der Shell, was bedeutet, dass Sie catalina.sh nicht aufrufen können, um Tomcat zu starten. Das distroless Bild eignet sich für die Ausführung ausführbarer JARs, wie z. B. bei Spring Boot oder Quarkus.
Im folgenden Beispiel wird die gleiche Version von Microsoft-Build von OpenJDK sowohl in der Buildphase als auch in der endgültigen Phase verwendet. Mit diesem Ansatz wird sichergestellt, dass Sie den Quellcode mit derselben Version des JDK erstellen, die von der Dienstbereitstellung tomcat verwendet wird, wodurch unerwartetes Verhalten aufgrund von Versionskonflikten vermieden wird.
Die folgende Abbildung zeigt den Multistage-Build und die Ereignisse in jeder Phase basierend auf den befehlen, die in der Dockerfile-Datei angegeben sind:
In Phase 0 wird Tomcat aus einem versionsspezifischen Apache-Archiv heruntergeladen, mit einer SHA-512-Prüfsumme überprüft und in ein Verzeichnis extrahiert, das durch eine Umgebungsvariable auf einem Ubuntu-Image angegeben wird. Die TOMCAT_VERSION Variable gibt die Freigabe an, und das TOMCAT_SHA512 Buildargument gibt die erwartete Prüfsumme an. Aktualisieren Sie beide Werte zusammen, wenn Sie eine neuere unterstützte Version auswählen. Docker kann die zwischengespeicherte Installationsschicht wiederverwenden, solange ihre Anweisungen und Eingaben unverändert sind. Die Tomcat-Installation wird zur Verwendung in die Zielumgebung kopiert.
In Phase 1 wird Maven auf einem Ubuntu-Image installiert, und die erstellten Quellcode- und Konfigurationsdateien werden vor dem Erstellen des Maven-Projekts kopiert. Jede Ebene wird zwischengespeichert, sodass das Betriebssystem-Image und die Maven-Image-Ebenen den Cache nutzen. Wenn Konfigurationsdateien, Quellcodedateien oder das Webverzeichnis aktualisiert werden, werden die Ebenen aus den Änderungen neu erstellt. Wenn der Build während der Kompilierung erfolgreich abgeschlossen wird, wird ein Artefakt namens AirlinesReservationSample-0.0.1-SNAPSHOT.war unter dem target-Verzeichnis generiert. Dieses Artefakt wird zur Verwendung in die Endumgebungsphase kopiert.
In der letzten Phase werden die Tomcat- und Java Artefakte aus Phase 0 bzw. Phase 1 in ein Microsoft-Build von OpenJDK 17-Image auf Azure Linux 3.0 kopiert. Ein Benutzer mit dem Namen app besitzt alle Dateien, die im Projekt verwendet werden, und die Anwendung wird auch als app Benutzer ausgeführt, statt mit root-Berechtigungen. Mit diesem Setup wird sichergestellt, dass das Containerimage sicher betrieben werden kann, ohne unnötige Berechtigungen zu erteilen. Schließlich wird die Portnummer 8080 verfügbar gemacht, und das skript catalina.sh wird ausgeführt, um Tomcat zu starten. Wenn dies auf Ihrem lokalen Docker Desktop ausgeführt wird, können Sie über die URL http://localhost:8080/AirlinesReservationSampledarauf zugreifen.
Verwenden Sie in containerize-and-deploy-Java-app-to-Azure/Project/Airlines einen installierten Text-Editor, um eine Datei mit dem Namen Dockerfile zu erstellen. Fügen Sie den folgenden Inhalt hinzu, und speichern Sie die Datei:
Important
Bevor Sie ein Bild erstellen, das Sie öffentlich verfügbar machen werden, überprüfen Sie die aktuelle unterstützte Tomcat 10.1.x-Version auf der Apache Tomcat-Downloadseite , und überprüfen Sie die Sicherheitshinweise. Aktualisieren Sie TOMCAT_VERSION und TOMCAT_SHA512 zusammen unter Verwendung der von Apache veröffentlichten Release-Informationen. Ein im Apache-Archiv verbleibendes Artefakt bedeutet nicht, dass seine Version aktuell oder empfohlen ist.
############################################
# Tomcat Intall stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat
ENV CATALINA_HOME=/usr/local/tomcat
# Configure the reviewed Tomcat version and checksum
ENV TOMCAT_VERSION=10.1.61
ARG TOMCAT_SHA512=35120a2b1182bac3d55438fbec0dc581d03b0f1c16ce692a930f3bb6a1097cf896b94b389152257071a87cb2928ac8c15f1bad08387c14acc7c17dbc1bb598fb
# Install Tomcat and required packages
RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates && \
curl -fSL \
"https://archive.apache.org/dist/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz" \
-o /tmp/tomcat.tar.gz && \
echo "${TOMCAT_SHA512} /tmp/tomcat.tar.gz" | sha512sum -c - && \
mkdir -p "${CATALINA_HOME}" && \
tar -xzf /tmp/tomcat.tar.gz --strip-components=1 -C "${CATALINA_HOME}" && \
rm /tmp/tomcat.tar.gz && \
apt-get remove --purge -y curl && \
apt-get autoremove -y && \
apt-get clean
############################################
# Build stage (Compiles with Java 17)
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build
WORKDIR /build
# Install Maven
RUN apt-get update && apt-get install -y maven && mvn --version
# Copy source code
COPY pom.xml .
COPY src ./src
COPY web ./web
# Build the project
RUN mvn clean package
############################################
# Package final stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-azurelinux
# Configure the location of the Tomcat installation
ENV CATALINA_HOME=/usr/local/tomcat
# Configure the path to the Tomcat binaries
ENV PATH=$CATALINA_HOME/bin:$PATH
# This is the user that runs the Tomcat process
USER app
# Copy the Tomcat installation from the Tomcat stage
COPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}
# Copy the Tomcat configuration files
COPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/conf
# Copy the compiled WAR file from the build stage
COPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.war
# Expose the default Tomcat port
EXPOSE 8080
# Start Tomcat
CMD ["catalina.sh", "run"]
Hinweis
Verwenden Sie die in dieser Lektion gezeigte Dockerfile-Datei für diese Übung. Die Anwendung muss nach webapps/AirlinesReservationSample.war kopiert werden, sodass die URLs in den folgenden Einheiten den /AirlinesReservationSample/ Kontext verwenden. Ein anderer WAR-Dateiname ändert den Standardmäßigen Tomcat-Anwendungskontext.
Die Dockerfile-Datei ist in drei Phasen unterteilt, die in den folgenden Tabellen beschrieben werden:
Die Tomcat-Installationsstufe:
Docker-Befehl BESCHREIBUNG FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcatlegt das Basisimage auf Microsoft-Build von OpenJDK 17 unter Ubuntu fest und benennt diese Phasetomcat. Hier wird Tomcat installiert.ENVENV CATALINA_HOME=/usr/local/tomcatlegt eine Umgebungsvariable für das Installationsverzeichnis von Tomcat fest.ENVENV TOMCAT_VERSION=10.1.61legt die Tomcat-Version fest, die für dieses Beispiel festgelegt ist. Überprüfen Sie unterstützte Versionen und aktualisieren Sie sie bei Bedarf zusammen mitTOMCAT_SHA512.ARGARG TOMCAT_SHA512liefert Apaches veröffentlichte SHA-512-Prüfsumme für das ausgewählte Archiv als Buildargument.RUNInstalliert curlund CA-Zertifikate und verwendet danncurl -fSL, um das versionsspezifische Apache-Archiv herunterzuladen.-flässt HTTP-Fehler fehlschlagen;-Lfolgt Weiterleitungen. Das Archiv wird mitsha512sum -c -überprüft, bevor es mit--strip-components=1nachCATALINA_HOMEextrahiert wird. Die&&Kette stoppt beim Fehler, anstatt Fehler während der Bereinigung zu maskieren. Schließlich entfernt es das Archiv und nicht benötigte Pakete und bereinigt den Paketcache.Die Buildphase, die mit Java 17 kompiliert wird:
Docker-Befehl BESCHREIBUNG FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS buildlegt das Basisimage auf Microsoft-Build von OpenJDK 17 unter Ubuntu fest und benennt diese Phasebuild. Diese Phase wird zum Kompilieren der Java-Anwendung verwendet.WORKDIRWORKDIR /buildlegt das Arbeitsverzeichnis im Container auf/build, auf das der Quellcode kopiert und kompiliert wird.RUNRUN apt-get update && apt-get install -y maven && mvn --versioninstalliert Maven, ein Für Java-Projekte verwendete Buildautomatisierungstool, und überprüft seine Installation.COPYCOPY pom.xml .kopiert die Maven-Konfigurationsdatei in das Arbeitsverzeichnis. Diese Datei ist für die Erstellung des Projekts unerlässlich.COPYCOPY src ./srckopiert das Quellcodeverzeichnis in den Container. Hier befindet sich der Java-Anwendungscode.COPYCOPY web ./webkopiert das Webressourcenverzeichnis in den Container. Dazu gehören Webanwendungsressourcen, die für den Build erforderlich sind.RUNRUN mvn clean packageführt den Maven-Buildprozess aus, der die Java-Anwendung kompiliert und in eine WAR-Datei verpackt.Die letzte Phase des Pakets:
Docker-Befehl BESCHREIBUNG FROMFROM mcr.microsoft.com/openjdk/jdk:17-azurelinuxlegt das Basisimage auf Microsoft-Build von OpenJDK 17 auf Azure Linux 3.0 fest, das für die endgültige Bereitstellung der Anwendung verwendet wird.ENVENV CATALINA_HOME=/usr/local/tomcatlegt die Umgebungsvariable für das Installationsverzeichnis von Tomcat fest, ähnlich der Installationsstufe.ENVENV PATH=$CATALINA_HOME/bin:$PATHfügt das Verzeichnis "Tomcat bin" zum SystemPATHhinzu, sodass Tomcat-Befehle problemlos ausgeführt werden können.USERUSER appGibt den Benutzer an, unter dem der Tomcat-Prozess ausgeführt wird, wodurch die Sicherheit verbessert wird, indem er nicht als Stammbenutzer ausgeführt wird.COPYCOPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}kopiert die Tomcat-Installation aus dertomcatPhase und legt den Besitz auf denappBenutzer fest.COPYCOPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/confkopiert die Tomcat-Benutzerkonfigurationsdatei in den Container und legt den Besitz auf denappBenutzer fest.COPYCOPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.warkopiert die kompilierte WAR-Datei aus derbuildPhase in das Tomcat-Webapps-Verzeichnis , wobei der Besitz auf denappBenutzer festgelegt wird.EXPOSEEXPOSE 8080Dokumente, aus denen hervorgeht, dass die Anwendung auf TCP-Port 8080 lauschen soll. Es wird kein Hostport veröffentlicht. Die nächste Einheit gibt den Port mit der Option-p 8080:8080aufdocker runfrei.CMDCMD ["catalina.sh", "run"]Gibt den Befehl an, um Tomcat zu starten, wenn der Container ausgeführt wird.
Weitere Informationen zur Dockerfile-Konstruktion finden Sie in der Dockerfile-Referenz.