dockermacosgoarm64delve

Debugging go HelloWorld api with docker and delve on MacBook Pro M2 and Goland


I have simple Hello World go application with single endpoint on :8080

I have dockerized it and added delve in Dockerfile

Then I run this app with docker-compose up --build -d and then docker ps it:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

3fc3f7f5ead7 kek-app "dlv exec ./main --l…" About an hour ago Up About an hour 0.0.0.0:8080->8080/tcp, 0.0.0.0:40000->40000/tcp kek-app-1

In my Goland IDE I created Go Remote configuration for localhost and 40000 port.

enter image description here

I've added breakpoints, but when I click on debug icon it says:

Debugger disconnected unexpectedly

enter image description here

Here is the code:

main.go:

package main

import (
    "fmt"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, World!")
}

func main() {
    http.HandleFunc("/", helloHandler)
    fmt.Println("Server is running on :8080...")
    http.ListenAndServe("0.0.0.0:8080", nil)

}

Dockerfile:

FROM --platform=linux/arm64 golang:1.22

WORKDIR /app

COPY go.mod ./

RUN go mod download

COPY . .

RUN go install github.com/go-delve/delve/cmd/dlv@latest

RUN go build -gcflags="all=-N -l" -o main .

EXPOSE 8080
EXPOSE 40000

CMD ["dlv", "exec", "./main", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "--continue", "--log", "--log-output=debug"]

docker-compose.yaml:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"  # Expose the application port
      - "40000:40000"  # Expose the debug port

go.mod:

module kek

go 1.22

Tried to fix it so many times that finally gave up. Any help appreciated

P.S. Maybe it somehow related with Macbook Pro M2 ?


Solution

  • There are multiple issues that can affect the outcome.

    ** Your golang image.** source. In my case it is valid in provided snippet, because I'm on mac arm64 and the default from golang:1.22 will also work. But at work it was a custom installation by our devops:

    RUN curl -O https://secure_host_from_work/go/1.22.1/go1.22.1.linux-amd64.tar.gz \
         && tar -C /usr/local -xzf go1.22.1.linux-amd64.tar.gz
    

    As you can see it is an amd64 and on mac pro m2 I have arm64 architecture. That is why debugger adds wrapper (rosetta) for correct translation:

    2025-02-03T12:18:21Z debug layer=debugger Adding target 12 "/usr/bin/rosetta-wrapper /usr/local/bin/app /usr/local/bin/app --config /usr/local/config.yml"
    

    And that translation makes it work incorrectly by not catching breakpoints.

    Check your logs. Make sure you use valid golang image.

    And the second problem is related to Goland itself. Goland recommends to use 40000 port number for debug and I listened to them. That was a mistake.

    lsof -i :40000
    COMMAND   PID       USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
    goland  29781 a.umahanov   30u  IPv6 0xb86c24b76737b926      0t0  TCP localhost:safetynetp (LISTEN)
    

    This port is busy by goland. And when you try to debug it and connect with your goland to the container on this port, there is a conflict that prevents port which is busy to be used. And you see message like

    Debugger disconnected unexpectedly

    So I changed port to 38888, image to arm64 (or to FROM goland:1.xx) and everything works perfectly.

    Don't make my mistakes and good luck!