Debugging von Java Apps in Docker Containern
Wie kann ich meine dockerisierte Java-Anwendung mit IntelliJ IDEA oder Eclipse debuggen? Und wie bekomme ich IntelliJ IDEA dazu, dass Änderungen am Code während des Debuggens automatisch neu compiliert und deployt werden, ohne dass der Debug-Prozess neu gestartet werden muss?

Dirk Randhahn
Teamleiter, Softwarearchitekt
Veröffentlicht am
24. Oktober 2022

Inhalt
Manchmal ist es hilfreich oder gar notwendig, das Remote-Debugging von Java Apps in Docker Containern (oder auch in einem Kubernetes-Cluster etc.) zu ermöglichen.
Damit das schnell und ohne großen Aufwand geht, sollte man das Remote-Debugging gleich von Anfang an unterstützen. Eine komfortable Möglichkeit dazu wird in diesem Beitrag gezeigt.
Dockerfile
Ein wesentlicher Unterschied zu vielen üblichen Dockerfiles für Java-Anwendungen ist die Tatsache, dass hier nicht das JAR direkt ausgeführt wird, sondern als Entrypoint ein Shell-Script angegeben wird:
FROM eclipse-temurin:17-jre-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
COPY entrypoint.sh entrypoint.sh
RUN chmod +x entrypoint.sh
USER 65534
ENTRYPOINT [ "./entrypoint.sh" ]
entrypoint.sh
Das Shell-Script ist für das Starten der Java-Anwendung zuständig und steuert abhängig von der Umgebungsvariable JAVA_DEBUG_PORT
, ob das Remote-Debugging auf dem angegebenen Port aktiviert oder deaktiviert ist:
#!/bin/sh
if [ x"${JAVA_DEBUG_PORT}" != x ]; then
echo "Debugger activated on internal port ${JAVA_DEBUG_PORT}"
JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=${JAVA_DEBUG_SUSPEND:=n},address=*:${JAVA_DEBUG_PORT}"
fi
cmd="java $JAVA_OPTS -jar app.jar"
echo "running $cmd"
sh -c "$cmd"
Wird die Umgebungsvariable JAVA_DEBUG_SUSPEND
auf den Wert „y
“ gesetzt, kann erzwungen werden, dass die Anwendung beim Start wartet, bis ein Debugger verbunden ist.
Über die Umgebungsvariable JAVA_OPTS
können zusätzliche Java-Parameter übergeben werden.
Zusätzliche Parameter für die Java-Anwendung können wie gewohnt in Zeile 7 ergänzt werden (z. B. -Dspring.profiles.active=prod
) oder eine weitere Umgebungsvariable kann hierfür eingeführt werden.
Container starten
Um den Container debuggen zu können, muss die Umgebungsvariable JAVA_DEBUG_PORT
(und wenn gewünscht auch JAVA_DEBUG_SUSPEND
) beim Start gesetzt werden:
$ docker run -d -e JAVA_DEBUG_PORT=7777 -p 7777:7777 YOUR-IMAGE
Was natürlich entsprechend auch bei der Verwendung von Kubernetes funktioniert:
apiVersion: apps/v1
kind: Deployment
spec:
strategy:
...
selector:
...
template:
metadata:
...
spec:
...
containers:
- name: YOUR-NAME
image: YOUR-IMAGE
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
allowPrivilegeEscalation: false
resources:
...
livenessProbe:
...
readinessProbe:
...
env:
- name: JAVA_DEBUG_PORT
value: "5005"
- name: JAVA_DEBUG_SUSPEND
value: "y"
Debuggen der Anwendung im Container
Danach kann man die Anwendung mit dem integrierten Debugger einer IDE wie Eclipse oder IntelliJ IDEA debuggen.
Dazu muss erst eine „Debug Configuration“ vom Typ „Remote Java Application“ (Eclipse) beziehungsweise „Remote JVM Debug“ (IntelliJ) angelegt werden.
Der Host muss in unserem Beispiel localhost sein, der Port 7777.
Mit Eclipse

Debug Configuration für das remote Debugging in Eclipse
Mit IntelliJ IDEA

Debug Configuration für das remote Debugging in IntelliJ IDEA
Verbinden des Debuggers mit dem Container
Um den Debugger mit der Anwendung im Container verbinden zu können muss der Port von Docker weitergeleitet werden. Das ist mit -p 7777:7777 im docker run Befehl schnell passiert.
Wenn der Container aber remote läuft, zum Beispiel in einem Kubernetes Cluster, muss der Port erst weitergeleitet werden:
$ kubectl port-forward YOUR-CONTAINER 7777:7777
Fazit
Erweitert man also das Dockerfile bzw das Run-Script nur um wenige Zeilen, ist es später lokal als auch remote über kubectl ganz einfach das Debugging von Java Apps in Docker zu aktivieren.

Hier schreibt
Dirk Randhahn
Als erfahrener Softwarearchitekt und Entwickler bei pep.digital liegt mein Fokus auf der Gestaltung hochwertiger Softwarearchitekturen und der Entwicklung leistungsstarker Java-Anwendungen. Zudem beschäftige ich mich auch mit anderen Themen wie Security, Build-Pipelines, Clean Code, ...
Wenn die Zeit es erlaubt, verfasse ich gelegentlich Blogbeiträge – immer dann, wenn ich denke, dass ich meinen Kollegen wertvolle Erkenntnisse mit auf den Weg geben kann.
Weitere interessante Artikel
Wir möchten hier nicht nur über Neuigkeiten aus dem Unternehmen berichten, sondern auch das Wissen und die Erfahrung unserer Experten teilen.

1 Jahr pep.digital – ein Beitrag von Alex
Alex ist seit einem Jahr bei pep.digital tätig. Als Software Entwickler sorgt er für stabile Lösungen in unseren Projekten. Er arbeitet in einem Kundenprojekt an der Entwicklung eines großen Lieferantenportals mit. Im Beitrag gibt er weitere Einblicke in sein Leben als Software-Entwickler bei pep.digital.
pep.digital

Zwei Köpfe, ein Ziel: Erfolgreiche Projektumsetzung mit Proxy Product Owner
In diesem Artikel zeigen wir, wie ein Proxy Product Owner die Arbeit in Softwareprojekten erleichtern kann. Ein Proxy PO unterstützt den Product Owner, indem er Aufgaben übernimmt, für die der Product Owner oft nicht die Zeit oder Erfahrung hat. Dazu gehört die Ermittlung von Kundenbedürfnissen, das Erstellen von User Stories, die Planung der nächsten Schritte und die Klärung fachlicher Fragen. So werden Engpässe vermieden und das Entwicklungsteam bleibt produktiv.

Karin Neubauer
Business Analystin