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
이미지 출처: https://github.com/golang/vscode-go/blob/master/docs/debugging.md#go-debug-extension-architecture-overview
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>
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" ]
#1을 통해 만들어진 image로 생성(Makefile
의 build_image_debug
rule 참조)
# image 생성 (Dockerfile.debug 사용)
$ docker buildx build . --load --platform linux/amd64 --tag dockebi-go:0.1.0 --file Dockerfile.debug
생성한 image의 container 실행(Makefile
의 run_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"
(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 │
└───────────────────────────────────────────────────┘
(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
(vscode) breakpoint가 있는 line이 호출되었을 때의 모습