1 июля 2020 г. Docker Debugger Delve Vscode Goland
Ранее мы обсуждали локальную отладку с помощью IDE GoLand. Теперь мы обсудим, как удалённо отлаживать программу, работающую внутри Docker-контейнера, используя Visual Studio Code и GoLand IDE.
При локальной отладке IDE управляет всем — компилирует программу, запускает её и подключается к ней.
Однако иногда может потребоваться выполнить удалённую отладку. В этом случае ваша программа должна запускаться независимо от IDE. Подготовка программы к удалённой отладке будет задачей разработчика или DevOps-инженера.
Это может показаться редким случаем использования, но вот ситуации, когда она может понадобиться:
Перед началом реализации удалённой отладки необходимо понимать, что ошибки легче исправлять на ранних этапах разработки. При локальной отладке вы можете запустить программу с помощью go run, delve debug или любой IDE. При удалённой отладке вам придётся ждать развёртывания программы в удалённой среде.
Инструмент отладки, используемый в IDE GoLand или Visual Studio Code, — это Delve.
Отладка Delve + IDE всегда работает следующим образом:
Delve — это инструмент командной строки. Все его параметры CLI определены здесь.
Помимо сетевого API, Delve также имеет опции отладки из командной строки для отладки напрямую из командной строки (без IDE). Однако мы не будем использовать эту опцию.
Итак, нам нужно запустить Delve и обеспечить удалённое подключение к нему из нашей IDE.
Для лучшего понимания этой статьи я создал репозиторий GitHub со всем связанным кодом.
Docker-контейнеры — популярный тип развёртывания. Недавно мы обсуждали создание минимального Docker-образа и развёртывание Docker Swarm. Docker-контейнеры можно использовать здесь для демонстрации удалённого подключения.
Давайте настроим Dockerfile:
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. В результирующем Docker-образе есть два файла: /dlv — Delve; /app — наша программа.
Флаги компиляции Go поддерживаются многими инструментами Go: build, clean, get, install, list, run, test. Благодаря этому бинарный файл Delve, полученный с помощью go get, также статически скомпилирован. По умолчанию бинарный файл Delve, скомпилированный в среде 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.
Содержимое 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. Указанные выше параметры передаются, чтобы Delve работал как сетевой сервер и включал подробное логирование.
Давайте вызовем docker-compose -f ./docker/debug/docker-compose.yml up и проверим логи. Эта команда также доступна как make docker-run-debug.
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" — позволяет VS Code подключиться к запущенному экземпляру Delve вместо запуска новой сессии отладки локальноport, host — сетевой хост и порт нашего Delve. Используя docker-compose, мы запустили Docker-контейнер локально и опубликовали его порт 2345 на хост (localhost)remotePath — один из критических параметров, который влияет на успешную установку точек останова. Это путь к папке с исходным кодом, которая использовалась на этапе компиляции. Мы скомпилировали наш бинарный файл в Dockerfile, используя WORKDIR /, поэтому наша директория — это корневая директория — оставим remotePath пустымПеред выполнением каких-либо действий в IDE давайте проверим, что наш Docker-контейнер сейчас работает.
Затем запустите задачу отладки “Attach”. Мы должны установить точки останова и убедиться, что они остаются на месте (визуально в IDE). Каждая установка точки останова отражается в логах Docker-контейнера — ошибок быть не должно.
Все настройки в этой IDE можно изменить в графическом интерфейсе, без редактирования файлов конфигурации. Важная вещь — включить интеграцию модулей:
Нажмите Run → Edit configurations, добавьте новую конфигурацию отладки и выберите “Go Remote”:
Так же, как и в VS Code, мы должны установить точки останова и убедиться, что они на месте. Мы должны проверить логи Docker-контейнера. Если есть какие-либо ошибки, например could not find file somedir/main.go, вам нужно включить интеграцию модулей Go.
Ранее мы рассматривали деплой бинарного файла программы через SSH на сервер
Сейчас мы рассмотрим как реализовать деплой Docker контейнера из Gitlab CI.
Read More → Docker Deploy Gitlab Ci/CdУтилита и пакет Go для ожидания открытия портов (TCP, UDP).
Read More → Tcp Udp DockerДавайте обсудим, как создать минимальный Docker образ для Go программы.
Read More → Docker Compilation Upx LdflagsОтладчик — это очень полезный и мощный инструмент. Он может помочь вам точно понять, что происходит в вашем коде, изучить новые проекты и избежать ненужных изменений отладочного кода.
Read More → Debugger Goland