Remote Debug Spring Boot App in a Docker Container using IntelliJ IDEA

Created: 2020-08-22 | 5 min


I had to setup a local environment for a Spring Boot application running in a Docker container. Naturally, I needed to find a way to debug my app, which is the step I want to explain here.

#Prerequisites

#Scope

#Create the project

Generate and Download a Spring Boot project with only "Spring Web" as a dependency.

Open the project in IntelliJ.

#Create the resource controller

Open the DemoApplication class and create a resource controller, in this example mapped with alias /echo, that is simply going to return the value from the request.

package com.ckinan.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class DemoApplication {

    @GetMapping("/echo")
    public String resource(@RequestParam(value = "value", defaultValue = "insert a 'value' query param") String value) {
    	return "echo: " + value;
    }

    public static void main(String[] args) {
    	SpringApplication.run(DemoApplication.class, args);
    }

}

#Package your app

Execute the following command manually to get the jar file of your project generated using maven.

./mvnw package

You should have the jar file created in the ./target folder. In this example, it should be under the name ./target/demo-0.0.1-SNAPSHOT.jar

#Create the Dockerfile

Create a Dockerfile in the root of the project.

FROM openjdk:14-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

We are giving the instruction to Docker to build an image from openjdk:14-jdk-alpine and copy our recently created jar file that will be used in our container.

#Build the image

Run the docker build command to create the Docker Image.

docker build -t ckina/demo-spring-boot-docker-debug .

The image will be created with the repository name ckina/demo-spring-boot-docker-debug, change that if you want.

#Remote debug your container

Choose one of the following ways to run your docker container: with docker run or docker-compose.

#With docker run

Execute the docker run command using the Docker Image we've just created.

docker run --name demo-spring-boot-docker-debug -e "JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" -p 8080:8080 -p 5005:5005 ckina/demo-spring-boot-docker-debug

#With docker-compose

Create a docker-compose.yml file and execute docker-compose.

version: '3.3'

services:
  spring-boot:
    container_name: demo-spring-boot-docker-debug
    build: .
    ports:
      - '8080:8080'
      - '5005:5005'
    environment:
      - JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

Options:

Run:

docker-compose up --build

Verify your endpoint is working by opening this in a browser: http://localhost:8080/echo?value=foo

It should give you echo: foo in the response of the call.

#Create the remote debug configuration in IntelliJ and attach the debugger

Go to Edit Configurations and create a Remote config:

Note: It's important to have the command line arguments matching with our configuration we introduced into our docker container. In this case this is what should match:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

Go back to your IDE and do the following:

  1. Set a breakpoint in your controller, right in the line where the string value is returned
  2. Click on the debug button
  3. You should have your IDE connected as the debugger of your Spring Boot application

Now execute one more time http://localhost:8080/echo?value=foo

The breakpoint in the IDE should be activated. We are done.

#Details on the command line argument for the Remote Debug

Here we have the details about the -agentlib:jdwp option we introduced in the environment variables of our docker container:

More details about the -agentlib:jdwp option: https://docs.oracle.com/en/java/javase/14/docs/specs/jpda/conninv.html