10.07.2020 docker debugger delve vscode goland
Ранее мы рассмотрели локальное использование отладчика в Goland IDE. В данной статье рассмотрим, как удаленно отладить программу, запущенную в Docker-контейнере из Visual Studio Code или Goland IDE.
При локальной отладке процессом полностью управляет IDE — компилирует программу и подключается к ней.
Иногда может потребоваться удаленная отладка — приложение запускается отдельно от IDE. Предварительная подготовка программы в данном случае ложится на плечи разработчика, а со стороны IDE необходимо подключиться к запущенной удаленно программе.
Почему это может потребоваться? Вероятно, это не слишком частый случай, но причины могут быть следующие:
Перед тем, как приниматься за удаленную отладку, помните, что
проще всего поправить баг на более ранних стадиях — локально.
Локально вы можете запустить программу мгновенно с помощью go run
или delve debug
или любой IDE; при работе с удаленным окружением
придется подготавливать программу, отладчик, ожидать загрузки программы на удаленном окружении -
все это будет отнимать ваше время, а значит, замедлять поиск ошибки.
Отладчик, используемый "под капотом" Goland IDE или Visual Studio Code, — Delve.
Отладка в IDE с помощью Delve всегда работает так:
Delve — утилита командной строки, полный список параметров которой описан здесь. Delve умеет как самостоятельно компилировать программу,
так и запускать ранее скомпилированную программу (в зависимости от параметров).
Delve также имеет интерфейс отладки из командной строки (для отладки без IDE),
однако данным функционалом мы пользоваться не будем.
Итак, нам необходимо запустить Delve c нашей программой и обеспечить удаленное подключение IDE к нему.
Для демонстрации удаленной отладки я подготовил репозиторий Github, который содержит весь исходный код демонстрируемой в статье программы.
Docker-контейнеры — популярный способ деплоя программ. Подготовка минимально возможного контейнера Docker, а также деплой c помощью docker swarm рассматривались ранее. В нашем случае подключение к программе, запущенной в Docker-контейнере, послужит демонстрацией удаленной отладки.
Подготовим Dockerfile с Delve и нашей программой:
FROM rhaps1071/golang-1.14-alpine-git AS build WORKDIR / COPY . . RUN CGO_ENABLED=0 go get -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv RUN CGO_ENABLED=0 go build -gcflags "all=-N -l" -o ./app FROM scratch COPY --from=build /go/bin/dlv /dlv COPY --from=build /app /app ENTRYPOINT [ "/dlv" ]
Здесь используется двухэтапная сборка и
статическая компиляция бинарных файлов для использования затем в Docker образе FROM scratch
с минимальным размером.
В нашем результирующем образе мы сохраняем бинарные файлы двух программ —
/go/bin/dlv
— Delve; /app
— наша программа.
Флаги сборки GO поддерживаются сразу многими утилитами -
build
, clean
, get
, install
, list
,
run
, test
.
Благодаря данной возможности, бинарник Delve, получаемый через go get
, также собирается статически.
По умолчанию, после сборки в окружении Alpine Linux
, он зависит от двух библиотек.
Проверить это можно через консольную команду ldd
:
ldd /go/bin/dlv /lib/ld-musl-x86_64.so.1 (0x7f761f8b7000) libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f761f8b7000)
Флаги -gcflags "all=-N -l"
, используемые для компиляции нашей программы,
необходимы для работы Delve с ней.
Для сборки контейнера можно использовать команду docker build -f ./docker/debug/Dockerfile -t debug .
,
которая также реализована как команда Makefile
с именем docker-build-debug
,
так что можно выполнить make docker-build-debug
.
Запускаем собранный контейнер с помощью docker-compose
,
что также как и сборка доступно через Makefile
— make docker-run-debug
.
Содержимое файла docker-compose.yml
:
version: "3" services: debug: build: dockerfile: docker/debug/Dockerfile context: ../../ ports: — 2345:2345 command: "--listen=:2345 --headless=true --log=true --log-output=debugger,debuglineerr,gdbwire,lldbout,rpc --accept-multiclient --api-version=2 exec ./app"
Так как ранее мы установили ENTRYPOINT
в образе как /dlv
,
то в параметре command
мы передаем только параметры для Delve.
Переданные параметры направлены на многократную удаленную отладку и подробное логгирование.
Вызываем docker-compose -f ./docker/debug/docker-compose.yml up
и изучаем логи контейнера:
Starting debug_debug_1 ... done Attaching to debug_debug_1 debug_1 | API server listening at: [::]:2345 debug_1 | 2020-07-10T13:36:06Z debug layer=rpc API server pid = 1 debug_1 | 2020-07-10T13:36:06Z info layer=debugger launching process with args: [./app]
Если в логах видим то, что сервер запущен на порту 2345, то все хорошо. Давайте теперь подключимся к нему из IDE.
В IDE мы должны открыть проект с исходниками отлаживаемой програмы.
Для добавления конфигурации удаленной отладки
создадим или отредактируем в проекте файл .vscode/launch.json
файл,
чтобы в нем была следующая секция конфигурации:
{ "version": "0.2.0", "configurations": [ { "name": "Attach", "type": "go", "request": "attach", "mode": "remote", "remotePath": "", "port":2345, "host":"127.0.0.1", "showLog": true, "trace": "log", "logOutput": "rpc" } ] }
"request": "attach"
— позволяет нашему IDE именно подключаться удаленно,
а не стартовать новую сессию отладки;port
,host
— порт и хост запущенного удаленно Delve.
Так как c помощью docker-compose
мы запустили Docker-контейнер локально и пробросили порт 2345
на наш локальный компьютер, то подключаемся к 127.0.0.1 или localhost.remotePath
— один из критически важных параметров,
влияющий на то, будут ли корректно ставиться breakpoints.
Это путь к папке с исходниками нашей программы при компиляции.
Мы компилировали нашу программу с помощью Dockerfile, находясь в корневой директории (
WORKDIR /
).
Следовательно, наша директория компиляции — корневая, поэтому
оставляем поле remotePath
пустым.Итак, перед действиями в IDE, проверим, что отлаживаемый нами контейнер работает.
Далее средствами VSCode запускаем задачу отладки "Attach":
Мы можем ставить breakpoints и они должны оставаться видимыми в IDE, при этом в debug console отображается наше сетевое взаимодействие с Delve в контейнере и в нем не должно быть ошибок.
При удаленной отладке у нас должен быть запущен наш Docker-контейнер с Delve и нашей программой, а в IDE открыт проект с исходниками программы.
Для данной IDE настройка проходит визуально. Важно — необходимо включить GO modules integration в настройках IDE:
Далее — главное меню — Run — Edit configurations, добавляем новую конфигурации откладки, выбираем "Go Remote":
Аналогично VSCode, после подключения отладчиком, ваши breakpoints должны ставится.
При возникновении проблем, обратите внимание на консоль контейнера, на сообщения о папках,
например, could not find file somedir/main.go
.
В этом случае необходимо включить GO modules integration.