Pull to refresh

Удалённая отладка Go-приложений в Kubernetes с помощью Delve

Level of difficultyMedium

В этой статье я расскажу, как отлаживать сервисы, написанные на Go и запущенные в Kubernetes.

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

Что делать? На помощь приходит Delve — отладчик для языка Go. Ниже я покажу, как шаг за шагом настроить удалённую отладку приложения прямо в кластере Kubernetes.

Шаг 1. Простое Go-приложение

Начнём с небольшой программы на Go. Это HTTP-сервер с одним хендлером, принимающим параметр name.

package main  
  
import (  
    "fmt"  
    "log"    
    "net/http"
)  
  
func main() {  
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {  
       name := r.URL.Query().Get("name")  
       if name == "" {  
          name = "debugger"  
       }  
  
       fmt.Printf("Received request with name: %s\n", name)  
  
       fmt.Fprintf(w, "Hello, %s!\n", name)  
    })  
  
    port := ":8080"  
    fmt.Println("Server is running on http://localhost" + port)  
    if err := http.ListenAndServe(port, nil); err != nil {  
       log.Fatalf("Server failed to start: %v", err)  
    }  
}

Dockerfile для сборки этого сервиса:

FROM golang:1.24.2-alpine3.21 AS builder  
  
WORKDIR /app  
  
COPY . .  
RUN go build -o server .  
  
FROM alpine:3.21  
  
WORKDIR /app  
  
COPY --from=builder /app/server .  
  
EXPOSE 8080  
  
CMD ["./server"]

Шаг 2. Отладка внутри Kubernetes

Для примера я использую Minikube — удобный способ развернуть локальный кластер одной командой. Helm-чарты и команды для деплоя вы найдёте на GitHub

Представим, что в нашем приложении баг, и мы хотим его отладить прямо в Kubernetes.

Для этого немного модифицируем Dockerfile: установим Delve и будем запускать бинарь через него. Отладчик будет слушать порт 40000.

FROM golang:1.24.2-alpine3.21 AS builder  
  
WORKDIR /app  

# Установка Delve
RUN go install github.com/go-delve/delve/cmd/dlv@v1.24  
  
COPY . .  
RUN go build -o server .  
  
FROM alpine:3.21  
  
WORKDIR /app  
  
COPY --from=builder /app/server .  
COPY --from=builder /go/bin/dlv ./  
  
EXPOSE 8080  
  
#CMD ["./server"]

# Запуск бинарного файла с помощью Delve
CMD ["./dlv", "--headless=true", "--accept-multiclient", "--continue", "--listen=0.0.0.0:40000", "--api-version=2", "exec", "./server", "--log"]

Перекатим наше приложение. В логах увидим сообщения от Delve

API server listening at: [::]:40000
2025-04-12T16:04:01Z warn layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
2025-04-12T16:04:01Z info layer=debugger launching process with args: [./server]
2025-04-12T16:04:01Z debug layer=debugger Adding target 17 "/app/server"
2025-04-12T16:04:01Z debug layer=debugger continuing
2025-04-12T16:04:01Z debug layer=debugger ContinueOnce

Шаг 3. Прокидываем порт на локалку

Теперь подключим порт отладчика из пода к локальной машине. Важно: прокидываем не порт сервиса, а порт Delve 40000.

kubectl port-forward pod/simple-server-69676f6446-sslk9 40000:40000

Шаг 4. Подключаемся из IDE

Открываем GoLand (или VS Code) и добавляем новую конфигурацию запуска:
Run → Edit Configurations → Go Remote
Параметры:

  • Host: localhost

  • Port: 40000

  • On disconnect: Leave it running

Конфигурация запуска Go remote для Delve
Конфигурация запуска Go remote для Delve

Шаг 5. Ставим breaking point и дебажим

Жмём кнопку Debug, ставим breakpoint и отправляем запрос:

Breaking point
Breaking point
curl http://127.0.0.1:62004\?name\=Alice

И — ура! — программа останавливается на breaking point'е прямо в IDE. Можно смотреть переменные, ходить по стеку, делать всё как при локальном дебаге — только теперь приложение живёт в Kubernetes.

Удалённая отладка в работе
Удалённая отладка в работе

Что делать, если у меня несколько реплик приложения?

Ничего сложного. Вам нужно прокинуть порты для каждой реплики, например:

  • 40000 -> 40000 для первой реплики

  • 40000 -> 40001 для второй реплики

  • 40000 -> 40002 для третьей реплики

Затем в IDE создаёте несколько конфигураций запуска Go Remote с разными портами и включаете их одновременно. Включится дебаг той реплики, на которую прийдёт запрос.

Заключение

Теперь вы можете отлаживать Go-приложения, запущенные в Kubernetes, не выходя из своей IDE. Это невероятно удобно при работе с багами, которые не воспроизводятся локально.

⚠️ Важно: не используйте такую отладку в production-среде. Delve не шифрует соединения и не требует авторизации, так что использовать его безопасно только в dev/staging окружениях.

Go-сервис, helm-чарты и инструкцию по запуску в Minikube можно найти на GitHub. Пишите в комментариях пользовались ли вы таким способом раньше!

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.