Добавить в корзинуПозвонить
Найти в Дзене

Как подключить Debugger к Spring Boot в Docker и не оставить дыру в Production

При разработке Spring Boot-приложений в Docker часто возникает необходимость подключить отладчик из IDE. Это позволяет ставить точки останова, анализировать выполнение кода и быстрее находить ошибки. Но здесь есть важный нюанс. Отладка должна работать только в среде разработки. В production debug-порт необходимо полностью отключать. Разберём простой и безопасный способ организации удалённой отладки через Docker Compose и NetBeans. Многие разработчики добавляют параметры JDWP прямо в Dockerfile. На первый взгляд это удобно: контейнер всегда готов к подключению отладчика. Однако такой подход имеет недостаток. Если тот же образ попадёт в production, вместе с ним будет запущен и debug-порт. Гораздо правильнее использовать разные конфигурации для разных сред: Поэтому Dockerfile должен оставаться универсальным. Базовый Dockerfile выглядит максимально просто: FROM eclipse-temurin:21-jdk
WORKDIR /app
COPY build/libs/app-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
Оглавление

При разработке Spring Boot-приложений в Docker часто возникает необходимость подключить отладчик из IDE. Это позволяет ставить точки останова, анализировать выполнение кода и быстрее находить ошибки.

Но здесь есть важный нюанс. Отладка должна работать только в среде разработки. В production debug-порт необходимо полностью отключать.

Разберём простой и безопасный способ организации удалённой отладки через Docker Compose и NetBeans.

Почему не стоит включать Debug в Dockerfile

Многие разработчики добавляют параметры JDWP прямо в Dockerfile. На первый взгляд это удобно: контейнер всегда готов к подключению отладчика.

Однако такой подход имеет недостаток. Если тот же образ попадёт в production, вместе с ним будет запущен и debug-порт.

Гораздо правильнее использовать разные конфигурации для разных сред:

  • в разработке отладка включена;
  • в production полностью отключена.

Поэтому Dockerfile должен оставаться универсальным.

Dockerfile без настроек отладки

Базовый Dockerfile выглядит максимально просто:

FROM eclipse-temurin:21-jdk

WORKDIR /app

COPY build/libs/app-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080

CMD ["java", "-jar", "app.jar"]

Здесь нет никаких параметров JDWP. Контейнер просто запускает Spring Boot приложение.

Основной Docker Compose для Production

Создаём стандартный файл docker-compose.yml:

services:
app:
build: .
ports:
- "8080:8080"

В этом режиме наружу публикуется только HTTP-порт приложения.

Никакой удалённой отладки нет.

Отдельная конфигурация для разработки

Теперь создадим файл docker-compose.dev.yml, который будет использоваться только локально.

services:
app:
ports:
- "8080:8080"
- "5005:5005"

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

Переменная JAVA_TOOL_OPTIONS передаёт JVM параметры запуска и включает JDWP-сервер на порту 5005.

Именно к этому порту будет подключаться NetBeans.

Запуск в режиме разработки

Для локальной работы запускаем сразу два compose-файла:

docker compose \
-f docker-compose.yml \
-f docker-compose.dev.yml \
up -d --build

После старта контейнера JVM начнёт слушать порт 5005 и будет готова принимать подключения отладчика.

Запуск в Production

На сервере используется только основной compose-файл:

docker compose -f docker-compose.yml up -d

Поскольку dev-конфигурация не подключается, порт отладки отсутствует.

Это именно то поведение, которое требуется в production.

Подключаем NetBeans

Откройте меню:

Debug → Attach Debugger

В настройках укажите:

  • Debugger: JPDA Debugger
  • Host: localhost
  • Port: 5005

После нажатия кнопки Attach IDE подключится к JVM внутри контейнера.

Теперь можно использовать breakpoints так же, как при обычном запуске приложения.

Проверяем, что всё работает

Самый простой способ проверки:

  1. Поставить breakpoint в коде.
  2. Отправить HTTP-запрос в приложение.
  3. Убедиться, что выполнение остановилось на точке останова.

Если код остановился в нужном месте, значит удалённая отладка настроена корректно.

Проверка через логи контейнера

Также полезно проверить логи:

docker logs <container>

Если JDWP успешно запустился, вы увидите сообщение:

Listening for transport dt_socket at address: 5005

Это означает, что JVM ожидает подключения отладчика.

Что означают suspend=n и suspend=y

Параметр suspend определяет поведение JVM при старте.

suspend=n

В этом режиме приложение запускается сразу.

Даже если отладчик ещё не подключён, Spring Boot начнёт работу как обычно.

Такой вариант используется чаще всего.

suspend=y

В этом режиме JVM останавливается на старте и ждёт подключения отладчика.

Приложение не начнёт запускаться, пока IDE не подключится к процессу.

Этот режим полезен, если необходимо исследовать:

  • проблемы во время запуска приложения;
  • ошибки создания Spring Bean;
  • исключения, возникающие на ранних этапах инициализации.

Пример настройки:

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

Если отладчик не подключается

Чаще всего проблема связана с одной из трёх причин:

  • порт 5005 не проброшен наружу;
  • контейнер не был пересобран;
  • используется старый Docker-образ.

Проверьте список контейнеров:

docker ps

В выводе должна присутствовать строка примерно такого вида:

0.0.0.0:5005->5005/tcp

Если её нет, значит порт не опубликован.

Если breakpoint не срабатывает

Обычно это происходит тогда, когда код в IDE отличается от кода, который находится внутри JAR-файла.

Также причиной может быть запуск старой версии контейнера.

В большинстве случаев помогает полная пересборка:

docker compose down
docker compose up -d --build

После пересборки точки останова начинают работать корректно.

Почему нельзя держать Debug включённым в Production

JDWP открывает специальный управляющий порт JVM.

Через него можно подключаться к процессу и выполнять удалённую отладку.

Если такой порт случайно окажется доступен извне, это создаёт серьёзный риск безопасности.

Поэтому хорошей практикой считается:

  • не публиковать порт 5005 наружу;
  • не включать JDWP постоянно;
  • хранить настройки отладки только в dev-конфигурации.

Вывод

Безопасная схема выглядит очень просто.

Dockerfile содержит только запуск приложения и ничего не знает об отладке.

Основной файл docker-compose.yml используется для production и не открывает debug-порт.

Файл docker-compose.dev.yml подключается только во время разработки и включает JDWP на порту 5005.

В результате разработчик получает удобную удалённую отладку через NetBeans, а production остаётся защищённым и не содержит лишних открытых сервисов.