title: "**Docker 및 Remote에서 동작하는 Golang App Debugging**"
description: "**Docker 및 Remote에서 동작하는 Golang App Debugging**"
cleanUrl: /sw-engineer/debug-golang-app-docker-remote
ogImage: "<https://anyflower.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F7570d2fc-66b1-4e23-bb3c-ff7b56842b0d%2F26f0111f-b356-4809-803c-dbafb8889f3d%2FUntitled.png?table=block&id=14054cfc-097d-4d6b-9c37-4196ae154755&spaceId=7570d2fc-66b1-4e23-bb3c-ff7b56842b0d&width=2000&userId=&cache=v2>"
floatFirstTOC: right

Motivation

Idea

이미지 출처: https://github.com/golang/vscode-go/blob/master/docs/debugging.md#go-debug-extension-architecture-overview

이미지 출처: https://github.com/golang/vscode-go/blob/master/docs/debugging.md#go-debug-extension-architecture-overview

Requirement

target App은 반드시 debug info를 포함한 상태로 build되어야 함(그래야 debugger가 debugging symbol을 사용 가능. 아래 설정 방법 내 코드 중 RUN CGO_ENABLED=0 go build -gcflags "all=-N -l" . 참조)

설정 방법

<aside> 💡 아래 코드는 하기 dockebi-go 란 sample app의 일부

https://github.com/anyflow/dockebi-go

</aside>

  1. target App container image build에서의 동작(in Dockerfile.debug)

    ...
    # delve 설치
    RUN CGO_ENABLED=0 go install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@latest
     
    ...
    # target App 빌드 시 debug 정보 유지
    RUN CGO_ENABLED=0 go build -gcflags "all=-N -l" .
     
    ...
     
    # delve를 통해서 target을 실행(실행 주체는 delve, delve parameter로 target App 설정)
    ENTRYPOINT [ "/go/bin/dlv" ]
    CMD [ "--listen=:4000", "--headless=true", "--log=true", "--accept-multiclient", "--api-version=2", "exec", "/app/dockebi-go" ]
    
  2. #1을 통해 만들어진 image로 생성(Makefilebuild_image_debug rule 참조)

    # image 생성 (Dockerfile.debug 사용)
    $ docker buildx build . --load --platform linux/amd64 --tag dockebi-go:0.1.0 --file Dockerfile.debug
    
  3. 생성한 image의 container 실행(Makefilerun_docker rule 참조)

    ❯ make run_docker
    docker run --rm -p 3000:3000 -p 4000:4000 --name dockebi-go dockebi-go:0.1.0
    API server listening at: [::]:4000
    2023-12-06T08:51:52Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
    2023-12-06T08:51:52Z info layer=debugger launching process with args: [/app/dockebi-go]
    2023-12-06T08:51:52Z debug layer=debugger Adding target 12 "/app/dockebi-go"
    
  4. (vscode의 경우) target App의 source code를 열고, 다음 launch configuration으로 실행(launch.json 에 아래 configuration 추가. 경우 local내 docker에서 동작)

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Remote Docker App",
                "type": "go",
                "request": "attach",
                "mode": "remote",
                "port": 4000,
                "host": "127.0.0.1"
            }
        ]
    }
    

    실행 직후의 모습(in server)

    ❯ make run_docker
    docker run --rm -p 3000:3000 -p 4000:4000 --name dockebi-go dockebi-go:0.1.0
    API server listening at: [::]:4000
    2023-12-06T08:51:52Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
    2023-12-06T08:51:52Z info layer=debugger launching process with args: [/app/dockebi-go]
    2023-12-06T08:51:52Z debug layer=debugger Adding target 12 "/app/dockebi-go"
    2023-12-06T08:52:51Z info layer=debugger created breakpoint: &api.Breakpoint{ID:2, Name:"", Addr:0x8ec179, Addrs:[]uint64{0x8ec179}, AddrPid:[]int{12}, File:"/app/main.go", Line:13, FunctionName:"main.main.func1", ExprString:"", Cond:"", HitCond:"", HitCondPerG:false, Tracepoint:false, TraceReturn:false, Goroutine:false, Stacktrace:0, Variables:[]string(nil), LoadArgs:(*api.LoadConfig)(0xc001620720), LoadLocals:(*api.LoadConfig)(0xc001620750), WatchExpr:"", WatchType:0x0, VerboseDescr:[]string(nil), HitCount:map[string]uint64{}, TotalHitCount:0x0, Disabled:false, UserData:interface {}(nil)}
    2023-12-06T08:52:51Z debug layer=debugger continuing
    2023-12-06T08:52:51Z debug layer=debugger ContinueOnce
    
     ┌───────────────────────────────────────────────────┐ 
     │                   Fiber v2.51.0                   │ 
     │               <http://127.0.0.1:3000>               │ 
     │       (bound on host 0.0.0.0 and port 3000)       │ 
     │                                                   │ 
     │ Handlers ............. 3  Processes ........... 1 │ 
     │ Prefork ....... Disabled  PID ................ 12 │ 
     └───────────────────────────────────────────────────┘
    
  5. (vscode) source code에 breakpoint를 넣기. 아래는 넣는 즉식 찍히는 로그

     ┌───────────────────────────────────────────────────┐ 
     │                   Fiber v2.51.0                   │ 
     │               <http://127.0.0.1:3000>               │ 
     │       (bound on host 0.0.0.0 and port 3000)       │ 
     │                                                   │ 
     │ Handlers ............. 3  Processes ........... 1 │ 
     │ Prefork ....... Disabled  PID ................ 12 │ 
     └───────────────────────────────────────────────────┘ 
    
    2023-12-06T08:56:05Z debug layer=debugger halting
    2023-12-06T08:56:05Z debug layer=debugger callInjection protocol on:
    2023-12-06T08:56:05Z debug layer=debugger       12 PC=0x471d83
    2023-12-06T08:56:05Z debug layer=debugger       21 PC=0x471d83
    2023-12-06T08:56:05Z debug layer=debugger       22 PC=0x471d83
    2023-12-06T08:56:05Z debug layer=debugger       23 PC=0x471d83
    2023-12-06T08:56:05Z debug layer=debugger       24 PC=0x40538e
    2023-12-06T08:56:05Z info layer=debugger created breakpoint: &api.Breakpoint{ID:2, Name:"", Addr:0x8ec179, Addrs:[]uint64{0x8ec179}, AddrPid:[]int{12}, File:"/app/main.go", Line:13, FunctionName:"main.main.func1", ExprString:"", Cond:"", HitCond:"", HitCondPerG:false, Tracepoint:false, TraceReturn:false, Goroutine:false, Stacktrace:0, Variables:[]string(nil), LoadArgs:(*api.LoadConfig)(0xc0014ca780), LoadLocals:(*api.LoadConfig)(0xc0014ca7b0), WatchExpr:"", WatchType:0x0, VerboseDescr:[]string(nil), HitCount:map[string]uint64{}, TotalHitCount:0x0, Disabled:false, UserData:interface {}(nil)}
    2023-12-06T08:56:05Z debug layer=debugger continuing
    2023-12-06T08:56:05Z debug layer=debugger ContinueOnce
    
  6. (vscode) breakpoint가 있는 line이 호출되었을 때의 모습

    Untitled