Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Container bieten eine konsistente, portable Umgebung für Ihre Java-Anwendungen in allen Entwicklungs-, Test- und Produktionsphasen. In diesem Artikel werden Containerisierungskonzepte für Java-Anwendungen vorgestellt und Sie werden durch das Erstellen, Debuggen, Optimieren und Bereitstellen von containerisierten Java-Anwendungen in Azure Container Apps geführt.
In diesem Artikel lernen Sie grundlegende Containerisierungskonzepte für Java-Entwickler und die folgenden Fähigkeiten kennen:
- Einrichten Ihrer Entwicklungsumgebung für containerisierte Java-Anwendungen.
- Erstellen von Dockerfiles, die für Java-Workloads optimiert sind.
- Konfigurieren lokaler Entwicklungsworkflows mit Containern.
- Debuggen von containerisierten Java-Anwendungen.
- Optimierung von Java-Containern für die Produktion.
- Bereitstellen Ihrer containerisierten Java-Anwendungen in Azure Container Apps.
Durch die Containerisierung Ihrer Java-Anwendungen erhalten Sie konsistente Umgebungen, eine vereinfachte Bereitstellung, eine effiziente Ressourcennutzung und eine verbesserte Skalierbarkeit.
Container für Java-Anwendungen
Container verpacken Anwendungen mit ihren Abhängigkeiten, um die Konsistenz in allen Umgebungen zu gewährleisten. Für Java-Entwickler bedeutet dies, die Anwendung, ihre Abhängigkeiten, das Java Runtime Environment/Java Development Kit (JRE/JDK) und die Konfigurationsdateien in einer einzigen, portablen Einheit zu bündeln.
Die Containerisierung hat entscheidende Vorteile gegenüber der Virtualisierung und eignet sich daher ideal für die Cloud-Entwicklung. Im Gegensatz zu einer virtuellen Maschine wird ein Container auf dem Host-Betriebssystem-Kernel eines Servers ausgeführt. Dies ist vorteilhaft für Java-Anwendungen, die bereits in der Java Virtual Machine (JVM) laufen. Die Containerisierung von Java-Anwendungen führt zu einem minimalen Mehraufwand und bietet erhebliche Vorteile bei der Bereitstellung.
Das Container-Ökosystem umfasst die folgenden Schlüsselkomponenten:
- Bilder - die Blaupausen.
- Container – ausgeführte Instanzen.
- Registrierungen - wo Bilder gespeichert werden.
- Orchestratoren – Systeme, die Container in großem Umfang verwalten.
Docker ist die beliebteste Containerisierungsplattform und wird im Azure-Ökosystem durch Azure Container Apps gut unterstützt.
Einrichten Ihrer Entwicklungsumgebung
In diesem Abschnitt erfahren Sie, wie Sie die erforderlichen Tools installieren und Ihre Entwicklungsumgebung konfigurieren, um containerisierte Java-Anwendungen zu erstellen, auszuführen und zu debuggen.
Installieren erforderlicher Tools
Zum Containerisieren von Java-Anwendungen müssen die folgenden Tools auf Ihrem Entwicklungscomputer installiert sein:
- Docker Desktop. Stellt die Docker-Engine, die CLI und Docker Compose für Windows oder macOS bereit.
- Visual Studio Code. Verfügbar als kostenloser Code-Editor.
- Die folgenden Visual Studio Code-Erweiterungen:
- Docker-Erweiterung zur Verwaltung von Containern.
- Java Extension Pack für die Java-Entwicklung.
- Dev Container für die Entwicklung innerhalb von Containern.
Überprüfen Sie Ihre Installation mit den folgenden Befehlen:
docker --version
docker compose version
Konfigurieren von Visual Studio Code für die Containerentwicklung
Konfigurieren Sie für die Java-Entwicklung in Containern Visual Studio Code, indem Sie das Java Extension Pack installieren und Ihr JDK einrichten. Mit der Dev Containers-Erweiterung können Sie einen beliebigen Ordner in einem Container öffnen und den vollständigen Funktionsumfang von Visual Studio Code in diesem Container verwenden.
Damit Visual Studio Code automatisch einen Entwicklungscontainer erstellt und eine Verbindung mit ihm herstellt, erstellen Sie in Ihrem Projekt eine devcontainer.json-Datei .devcontainer/ .
Die folgende Beispielkonfiguration definiert beispielsweise einen Java-Build:
{
"name": "Java Development",
"image": "mcr.microsoft.com/devcontainers/java:21",
"customizations": {
"vscode": {
"extensions": [
"vscjava.vscode-java-pack",
"ms-azuretools.vscode-docker"
]
}
},
"forwardPorts": [8080, 5005],
"remoteUser": "vscode"
}
Diese Konfiguration verwendet das Java-Entwicklungscontainerimage von Microsoft, fügt wichtige Erweiterungen hinzu und leitet sowohl den Anwendungsport 8080als auch den Debugport weiter. 5005
Dockerfile erstellen
Eine Dockerfile enthält Anweisungen zum Erstellen eines Docker-Images. Für Java-Anwendungen enthält das Dockerfile in der Regel die folgenden Komponenten:
- Ein Basisimage mit dem JDK oder JRE.
- Anweisungen zum Kopieren von Anwendungsdateien.
- Befehle zum Festlegen von Umgebungsvariablen.
- Konfigurationen von Einstiegspunkten.
Wählen Sie ein Basisimage aus
Die Wahl des richtigen Basisbildes ist entscheidend. Ziehen Sie diese Optionen in Betracht:
| BESCHREIBUNG | Name | Bemerkungen |
|---|---|---|
| Microsoft Java Entwicklung Bild | mcr.microsoft.com/java/jdk:21-zulu-ubuntu |
Vollständiges JDK und optimiert für Azure |
| Microsoft Java Produktionsbild | mcr.microsoft.com/java/jre:21-zulu-ubuntu |
Nur Runtime und optimiert für Azure |
| Offizielles OpenJDK-Entwicklungsimage | openjdk:21-jdk |
Vollständiges JDK |
| Offizielles OpenJDK-Produktionsimage | openjdk:21-jre |
Nur Laufzeit |
Verwenden Sie für Entwicklungsumgebungen ein vollständiges JDK-Image. Verwenden Sie für die Produktion ein JRE- oder distributionsloses Image, um die Größe und Angriffsfläche Ihrer Anwendung zu minimieren.
Die Microsoft Java-Images verfügen über Azure-spezifische Optimierungen und werden regelmäßig mit Sicherheitspatches aktualisiert, sodass sie sich ideal für Anwendungen eignen, die auf Azure Container Apps abzielen.
Grundlegende Dockerfile-Beispiele
Das folgende Beispiel zeigt eine einfache Dockerfile für eine Java-Anwendung:
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Für Spring Boot-Anwendungen können Sie Ihre Dockerfile auf der folgenden Basis einrichten:
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Dspring.profiles.active=docker", "-jar", "app.jar"]
Verwenden Sie für Produktionsbereitstellungen das im folgenden Beispiel gezeigte JRE-Image, um die Größe Ihrer Anwendung zu reduzieren und die Angriffsfläche zu minimieren:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENV JAVA_OPTS="-Dserver.port=8080"
ENTRYPOINT ["java", ${JAVA_OPTS}, "-jar", "app.jar"]
Lokale Entwicklung mit Containern
Container sollen in verschiedenen Kontexten ausgeführt werden. In diesem Abschnitt lernen Sie einen lokalen Entwicklungsablauf für die Verwendung mit Containern kennen.
Verwenden von Docker Compose für Anwendungen mit mehreren Containern
Die meisten Java-Anwendungen interagieren mit Datenbanken, Caches oder anderen Diensten. Docker Compose hilft Ihnen, Anwendungen mit mehreren Containern mithilfe einer einfachen YAML-Konfigurationsdatei zu definieren und zu orchestrieren.
Was ist Docker Compose?
Docker Compose ist ein Tool, mit dem Sie die folgenden Aufgaben ausführen können:
- Definieren Sie Anwendungen mit mehreren Containern in einer einzigen Datei.
- Verwalten Sie den Anwendungslebenszyklus, einschließlich Start, Stopp und Neuerstellung.
- Pflegen Sie isolierte Umgebungen.
- Erstellen Sie Netzwerke für die Servicekommunikation.
- Beibehalten von Daten mithilfe von Volumes.
Beispiel: Java-Anwendung mit Datenbank
Die folgende compose.yml Datei konfiguriert eine Java-Anwendung mit einer PostgreSQL-Datenbank:
version: '3.8'
services:
app:
build: . # Build from Dockerfile in current directory
ports:
- "8080:8080" # Map HTTP port
- "5005:5005" # Map debug port
environment:
- SPRING_PROFILES_ACTIVE=dev
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/myapp
volumes:
- ./target:/app/target # Mount target directory for hot reloads
depends_on:
- db # Ensure database starts first
db:
image: postgres:13
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=myapp
ports:
- "5432:5432" # Expose PostgreSQL port
volumes:
- postgres-data:/var/lib/postgresql/data # Persist database data
volumes:
postgres-data: # Named volume for database persistence
Diese Datei weist die folgenden Merkmale auf:
- Services können sich gegenseitig über ihren Namen referenzieren,
dbz. B. in der JDBC-URL. - Docker Compose erstellt automatisch ein Netzwerk für die Dienste.
- Die Java-Anwendung wartet auf den Start der Datenbank, da
depends_on. - Die Datenbankdaten bleiben über Neustarts hinweg mit einem benannten Volume erhalten.
Allgemeine Docker Compose-Befehle
Nachdem Sie die compose.yml Datei erstellt haben, verwalten Sie die Anwendung mit den folgenden Befehlen:
# Build images without starting containers
docker compose build
# Start all services defined in compose.yml
docker compose up
# Start in detached mode (run in background)
docker compose up -d
# View running containers managed by compose
docker compose ps
# View logs from all containers
docker compose logs
# View logs from a specific service
docker compose logs app
# Stop all services
docker compose down
# Stop and remove volumes (useful for database resets)
docker compose down -v
Entwicklungsworkflow
Ein typischer Java-Entwicklungsworkflow mit Docker Compose umfasst die folgenden Schritte:
- Erstellen Sie die compose.yml Datei und die Dockerfile.
- Ausführen
docker compose up, um alle Dienste zu starten. - Nehmen Sie Änderungen an Ihrem Java-Code vor.
- Erstellen Sie Ihre Anwendung neu. Abhängig von der Konfiguration müssen Sie Ihre Container möglicherweise neu starten.
- Testen Sie die Änderungen in der containerisierten Umgebung.
- Wenn Sie fertig sind, führen Sie
docker compose down.
Ausführen einzelner Container mit Docker
In einfacheren Szenarien, in denen Sie nicht mehrere miteinander verbundene Dienste benötigen, können Sie den docker run Befehl verwenden, um einzelne Container zu starten.
Typisch für Java-Anwendungen sind folgende Docker-Befehle:
# Run a Java application JAR directly
docker run -p 8080:8080 myapp:latest
# Run with environment variables
docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" myapp:latest
# Run in detached mode (background)
docker run -d -p 8080:8080 myapp:latest
# Run with a name for easy reference
docker run -d -p 8080:8080 --name my-java-app myapp:latest
# Run with volume mount for persistent data
docker run -p 8080:8080 -v ./data:/app/data myapp:latest
Debuggen von containerisierten Anwendungen
Das Debuggen von containerisierten Java-Anwendungen ist manchmal eine Herausforderung, da Ihr Code in einer isolierten Umgebung innerhalb des Containers ausgeführt wird.
Standardmäßige Debugansätze gelten nicht immer direkt, aber mit der richtigen Konfiguration können Sie eine Remotedebugverbindung mit Ihrer Anwendung herstellen. In diesem Abschnitt erfahren Sie, wie Sie Ihre Container für das Debuggen konfigurieren, Ihre Entwicklungstools mit ausgeführten Containern verbinden und häufige Probleme im Zusammenhang mit Containern beheben.
Einrichten des Remotedebuggens
Zum Debuggen containerisierter Java-Anwendungen müssen Sie einen Debug-Port verfügbar machen und Ihre IDE so konfigurieren, dass eine Verbindung zu diesem Port hergestellt wird. Sie können diese Aufgaben ausführen, indem Sie die folgenden Schritte ausführen:
Um das Debuggen zu aktivieren, ändern Sie Ihre Dockerfile so, dass sie den folgenden Inhalt enthält:
Hinweis
Sie können stattdessen Ihren Containerstartbefehl ändern.
FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu WORKDIR /app COPY target/*.jar app.jar EXPOSE 8080 5005 ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "app.jar"]Konfigurieren Sie die launch.json Datei von Visual Studio Code so, dass eine Verbindung mit dem Debugport hergestellt wird, wie im folgenden Beispiel gezeigt:
{ "version": "0.2.0", "configurations": [ { "type": "java", "name": "Debug in Container", "request": "attach", "hostName": "localhost", "port": 5005 } ] }Starten Sie Ihren Container mit einem Port
5005, der Ihrem Host zugeordnet ist, und starten Sie dann den Debugger in Visual Studio Code.
Behandeln von Containerproblemen
Wenn sich Container nicht wie erwartet verhalten, können Sie die Protokolle Ihrer App überprüfen, um das Problem zu untersuchen.
Verwenden Sie die folgenden Befehle, um eine Problembehandlung für Ihre Anwendung durchzuführen. Bevor Sie diese Befehle ausführen, stellen Sie sicher, dass Sie die Platzhalter (<...>) durch Ihre eigenen Werte ersetzen.
# View logs
docker logs <CONTAINER_ID>
# Follow logs in real-time
docker logs -f <CONTAINER_ID>
# Inspect container details
docker inspect <CONTAINER_ID>
# Get a shell in the container
docker exec -it <CONTAINER_ID> bash
Aktivieren Sie bei Java-spezifischen Problemen die JVM-Flags für eine bessere Diagnose, wie im folgenden Beispiel gezeigt:
ENTRYPOINT ["java", "-XX:+PrintFlagsFinal", "-XX:+PrintGCDetails", "-jar", "app.jar"]
In der folgenden Tabelle sind häufige Probleme und die entsprechenden Lösungen aufgeführt:
| Fehler | Mögliche Lösung |
|---|---|
| Nicht genügend Arbeitsspeicher. | Erhöhen Sie die Speichergrenzwerte für Container |
| Verbindungstimeouts | Überprüfen Sie die Netzwerkkonfiguration auf Fehler. Überprüfen Sie Ports und Routingregeln. |
| Probleme mit Berechtigungen | Überprüfen Sie die Dateisystemberechtigungen. |
| Probleme mit dem Klassenpfad | Überprüfen Sie die JAR-Struktur und die Abhängigkeiten. |
Java-Container optimieren
Java-Anwendungen in Containern erfordern eine besondere Berücksichtigung für eine optimale Performance. Die JVM wurde entwickelt, bevor Container üblich waren. Die Verwendung von Containern kann zu Problemen bei der Ressourcenzuordnung führen, wenn sie nicht ordnungsgemäß konfiguriert sind.
Sie können die Leistung und Effizienz Ihrer containerisierten Java-Anwendungen erheblich verbessern, indem Sie die Speichereinstellungen optimieren, die Image-Größe optimieren und die Garbage Collection konfigurieren. In diesem Abschnitt werden grundlegende Optimierungen für Java-Container behandelt, wobei der Schwerpunkt auf der Speicherverwaltung, der Startzeit und der Ressourcenauslastung liegt.
JVM-Speicherkonfiguration in Containern
Die JVM erkennt die Speichergrenzen für Container in Java 8 nicht automatisch. Für Java 9+ ist die Containererkennung standardmäßig aktiviert.
Konfigurieren Sie Ihre JVM so, dass Container-Grenzwerte eingehalten werden, wie im folgenden Beispiel gezeigt:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
Die folgenden JVM-Flags sind für containerisierte Anwendungen wichtig:
-
-XX:MaxRAMPercentage=75.0. Legt den maximalen Heap als Prozentsatz des verfügbaren Arbeitsspeichers fest. -
-XX:InitialRAMPercentage=50.0. Legt die anfängliche Heap-Größe fest. -
-Xmxund-Xms. Diese Flags sind ebenfalls verfügbar, erfordern jedoch feste Werte.
Vorbereiten der Produktionsbereitstellung
Die Verlagerung containerisierter Java-Anwendungen in die Produktion erfordert Überlegungen, die über die grundlegende Funktionalität hinausgehen.
Produktionsumgebungen erfordern robuste Sicherheit, zuverlässige Überwachung, ordnungsgemäße Ressourcenzuweisung und Konfigurationsflexibilität.
In diesem Abschnitt werden die grundlegenden Vorgehensweisen und Konfigurationen behandelt, die zum Vorbereiten Ihrer Java-Container für den Einsatz in der Produktion erforderlich sind. Der Schwerpunkt des Abschnitts liegt auf Sicherheit, Zustandsprüfungen und Konfigurationsmanagement, um sicherzustellen, dass Ihre Anwendungen in der Produktion zuverlässig ausgeführt werden.
Bewährte Sicherheitsmethoden
Schützen Sie Ihre containerisierten Java-Anwendungen mit den folgenden Vorgehensweisen:
Standardmäßiger Sicherheitskontext. Führen Sie Ihre Anwendungen als Nicht-Root-Benutzer aus, wie im folgenden Beispiel gezeigt:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu WORKDIR /app COPY target/*.jar app.jar RUN addgroup --system javauser && adduser --system --ingroup javauser javauser USER javauser ENTRYPOINT ["java", "-jar", "app.jar"]Suchen Sie proaktiv nach Problemen. Überprüfen Sie Containerimages regelmäßig auf Sicherheitsrisiken, indem Sie den folgenden Befehl verwenden:
docker scan myapp:latestAktualität des Basisbildes. Halten Sie Ihre Basisimages auf dem neuesten Stand.
Geheime Verwaltung. Implementieren Sie eine ordnungsgemäße Verwaltung von Geheimnissen. Codieren Sie beispielsweise vertrauliche Daten nicht hartcodiert in Ihre Anwendung, und verwenden Sie nach Möglichkeit einen Schlüsseltresor.
Eingeschränkte Sicherheitskontexte. Wenden Sie das Prinzip der geringsten Rechte auf alle Sicherheitskontexte an.
Zugriff auf das Dateisystem. Verwenden Sie nach Möglichkeit schreibgeschützte Dateisysteme.
Gesundheitschecks und -überwachung
Überprüfen Sie die Anwendungsintegrität mit Tests , um sicherzustellen, dass Ihre Anwendung ordnungsgemäß ausgeführt wird.
Schließen Sie für Spring Boot-Anwendungen die Actuator-Abhängigkeit für umfassende Integritätsendpunkte ein, wie im folgenden Beispiel gezeigt:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Konfigurieren Sie Ihre Anwendung so, dass Protokolle in einem für Containerumgebungen geeigneten Format ausgegeben werden, z. B. JSON.
Bereitstellen in Azure Container Apps
In diesem Abschnitt erfahren Sie, wie Sie Ihre Java-Container für die Bereitstellung von Azure Container Apps vorbereiten, und es werden wichtige Konfigurationsüberlegungen erläutert.
Vorbereiten Ihres Containers für Azure
Port-Konfiguration. Stellen Sie sicher, dass Ihr Container den von Azure bereitgestellten Port überwacht, wie im folgenden Beispiel gezeigt:
FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu WORKDIR /app COPY target/*.jar app.jar ENV PORT=8080 EXPOSE ${PORT} CMD java -jar app.jar --server.port=${PORT}Sonde für Gesundheit. Implementieren Sie Integritätstests für die Live- und Bereitschaftsprüfungen von Azure.
Protokoll-Konfiguration. Konfigurieren Sie die Protokollierung für die Ausgabe in
stdout/stderr.Planen Sie für das Unerwartete. Richten Sie die ordnungsgemäße Behandlung des ordnungsgemäßen Herunterfahrens mit Timeoutkonfiguration ein. Weitere Informationen finden Sie unter Verwaltung des Anwendungslebenszyklus in Azure Container Apps.