Отладка Go внутри Docker с помощью VSCode

Возможность отладки — важный инструмент, который должен быть в арсенале разработчика. Хотя идеальным вариантом является отладка путем запуска приложения в естественном режиме, существуют сценарии, когда это невозможно или проблему необходимо воспроизвести в определенной среде.

Необходимые настройки для отладки приложения Go, запущенного в контейнере Docker, нетривиальны. В этой заметке я расскажу о конфигурации для достижения этой цели с помощью VSCode и отладчика Delve.

Рассмотрим это простое серверное приложение Go, которое прослушивает порт 80 и имеет простой обработчик на конечной точке GET /hello:

package main

import (
    "fmt"
    "net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
    fmt.Println("/hello endpoint called")
    fmt.Fprintf(w, "hellon")
}

func main() {
    http.HandleFunc("/hello", hello)
    fmt.Println("Server up and listening...")
    http.ListenAndServe(":80", nil)
}
Войти в полноэкранный режим Выйти из полноэкранного режима

И Docker-файл:

FROM golang:1.18-alpine
WORKDIR /app
EXPOSE 80

COPY hello.go ./
ENV GO111MODULE=off
RUN go build -o hello-app .

CMD [ "./hello-app" ]
Вход в полноэкранный режим Выйти из полноэкранного режима
  • Директива COPY просто копирует файлы с хоста на собираемый образ
    • Поскольку мы не работаем с модулями Go ENV GO111MODULE=off требуется для правильной сборки нашей программы
  • Наконец, CMD предоставляет Docker команду запуска для нашего приложения при запуске контейнера.

Соберите, запустите и запросите с помощью этих команд:

docker build . --tag hello-image
docker run --publish 80:80 --name hello-image hello-server
curl http://localhost/hello
Войти в полноэкранный режим Выйти из полноэкранного режима

Примечание: Docker Compose — более удобный инструмент для управления жизненным циклом контейнера, но для простоты я решил работать с Docker напрямую.

Delve предоставляет сервер, запущенный в контейнере Docker, к которому подключается VSCode, чтобы взаимодействовать с сеансом отладки.

Для этого необходимо создать новый Dockerfile с изменениями по сравнению с исходным. Мы назовем этот файл Dockerfile.debug:

FROM golang:1.18-alpine
EXPOSE 80 4000
WORKDIR /app
COPY hello.go ./

RUN CGO_ENABLED=0 go install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@latest

ENV GO111MODULE=off
RUN CGO_ENABLED=0 go build -gcflags "all=-N -l" -o hello-app .

CMD [ "/go/bin/dlv", "--listen=:4000", "--headless=true", "--log=true", "--accept-multiclient", "--api-version=2", "exec", "/app/hello-app" ]

Вход в полноэкранный режим Выход из полноэкранного режима

Здесь есть несколько отличий:

  • Мы устанавливаем пакет Delve с помощью RUN CGO_ENABLED=0 go install....
  • Мы добавили флаг -gcflags "all=-N -l" в команду сборки. Это нужно для отключения инлайнинга и оптимизаций, которые могут помешать отладке.

Нам также нужна пользовательская конфигурация отладки для VSCode, хранящаяся в .vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Remote Docker App",
            "type": "go",
            "request": "attach",
            "mode": "remote",
            "port": 4000,
            "host": "127.0.0.1"
        }
    ]
}
Войти в полноэкранный режим Выход из полноэкранного режима

Запуск отладочного контейнера требует немного других команд:

docker build . --tag debug-image --file Dockerfile.debug
docker run --publish 80:80 --publish 4000:4000 --name debug-server debug-image
Войти в полноэкранный режим Выйти из полноэкранного режима
  • Нестандартное имя файла Dockerfile.debug должно быть явно указано.
  • Существует дополнительный порт для публикации, 4000.
  • Мы используем другой тег изображения и имя контейнера, чтобы не перезаписывать исходную сборку.
    • Это ускоряет время сборки при переключении между отладочной и стандартной средой.

На этом этапе мы готовы к отладке нашей программы! Перейдите на вкладку Run and Debug, выберите Remote Docker App и нажмите кнопку Start Debugging play.

Установите точку останова в функции обработчика hello() нашей программы, нажав на поле слева от номера строки.

Наконец, curl сервер с помощью команды, предоставленной ранее, и наблюдаем, как отладчик останавливает выполнение!

Теперь, когда наша программа работает в отладочной сессии, мы получили ценный обзор внутренних процессов во время выполнения. Это значительно ускоряет цикл обратной связи при попытке понять, почему наша программа ведет себя не так, как предполагалось. Установка точек останова и пошаговое выполнение с помощью отладчика не требует особых усилий. В отличие от этого, добавление операторов печати, создание, запуск, а затем вызов приложения — гораздо более медленный процесс.

После этого вы можете свободно играть с многочисленными возможностями отладчика, которые предлагает VSCode: Установка точек останова, построчное выполнение с помощью Debug Actions, проверка значений переменных и так далее.

Вот некоторые ссылки для ознакомления:

  • Отладка с помощью VSCode
  • Мое микросервисное приложение Go в качестве рабочего примера этого упражнения

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

Оцените статью
devanswers.ru
Добавить комментарий