Недавно, создавая приложение для своих статей, я столкнулся со времязатратной проблемой. Локальная среда работала идеально, но, стоило упаковать Java-приложение в контейнер и запустить его, как случился сбой аутентификации. Думаю, многим знакома такая ситуация.

Усугублялась она невозможностью воссоздать проблему в локальных сеансах отладки. Добавить случайные логгеры для отслеживания ошибки тоже было не вариант, так как из API возвращалась ошибка «401» и служба не вызывалась. Да и пытаться исправлять ошибки и постоянно пересобирать образы Docker  —  особенно большие  —  очень времязатратно. Это все равно что наблюдать за высыханием краски: настолько медленно пересобирались образы Docker. Поэтому требовался другой подход.

А что, если отладить запущенный Java-контейнер? С этим вопросом для меня обнаружились возможности удаленной отладки IntelliJ IDEA.

Приступаем

Создав приложение для удаленной отладки, открываем в IntelliJ IDEA меню Edit Configurations («Редактировать конфигурации»). Нажимаем значок + и выбираем Remote JVM Debug («Удаленная отладка виртуальной машины Java»):

Видим такой экран:

Во вкладке Configuration меняем настройки под свои задачи:

  1. Name: содержательное название для конфигурации отладчика.
  2. Port: порт для отладчика, отличный от порта приложения. 
  3. JDK Version: выбираем правильную версию JDK, которая соответствует приложению. Автоматически генерируемые аргументы командной строки для удаленной виртуальной машины Java отличаются в зависимости от версии JDK.

Выбрав корректные настройки для приложения, копируем сгенерированные аргументы командной строки.

Создание Dockerfile

Используя эти аргументы, создадим Dockerfile. Вот, например, сгенерированный для моего приложения:

FROM maven:3.9.9 AS maven
LABEL authors="Muratcan Yeldan"

WORKDIR /opt/reminder
COPY . /opt/reminder
RUN mvn clean install

FROM eclipse-temurin:21-jre-alpine

ARG JAR_FILE=PetVaccineReminder.jar

WORKDIR /opt/reminder

COPY --from=maven /opt/reminder/target/${JAR_FILE} /opt/reminder/

ENTRYPOINT ["java","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000","-jar","PetVaccineReminder.jar"]

В ENTRYPOINT автосгенерированные аргументы командной строки добавляются после команды java. Но перед командой -jar, иначе удаленный отладчик не подключится.

Настройка docker-compose.yml

Теперь образ собирается и запускается напрямую или же для проекта создается docker-compose.yml, например, такой:

services:
reminder_service:
build:
dockerfile: Dockerfile
container_name: reminder_service
restart: on-failure
ports:
- "8085:8085"
- "8000:8000"
environment:
SPRING_PROFILES_ACTIVE: docker
depends_on:
postgres-app:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- backend-network

networks:
backend-network:
driver: bridge

Здесь указываются порт приложения 8085 и порт отладчика 8000. Запустив docker-compose.yml, продолжаем выполнение созданной ранее конфигурации удаленной отладки.

Запуск отладчика

Нажав в IntelliJ IDEA кнопку отладки Debug, увидим в консоли такой лог:

Значит, отладчик подключился к указанному порту. Дальше отладка приложения продолжается, как в локальной машине.

Проект находится здесь, в него включены технологии вроде Kafka и Keycloak.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Muratcan Yeldan: How to Remote Debug a Containerized Java Application with IntelliJ IDEA

Предыдущая статья5 концепций JavaScript, которые должен знать каждый разработчик
Следующая статьяКак стать дата-сайентистом в 2025 году?