I prefer adding print, rather than using break point.
But I can’t avoid it while some complex bug occurred. Or have to trace it into the third library codes.
I am developing micro-services in GoLang now. The services must running in Docker containers. At this time, debug will be a difficult stuff. We have to do it with Remote Debug Model.
- vscode — My favorite Coding IDE
- ms-vscode.go — The Go Plugin for vscode
- delve — A Debug tool for GoLang, and supports Remote Debug Model.
- Makefile — A Set of custom commands
- alpine — A mini Docker image, only 5MB
Start Up Container
Compile and run Docker Container with the files Makefile
& Dockerfile
. I compile my service
and dlv
to Linux binary files, because my OS is Mac. Then copy them into alpine
base container.
- Configure
Makefile
- Build GoLang file with argument
-gcflags “all=-N -l”
for supporting Debug. - Run container with arguments
-security-opt=”seccomp=unconfined” — cap-add=SYS_PTRACE
for closing security limit of Linux. - Run with
-p 20000:20000
for exposingdlv
server port, which vscode will to connect to.
NAME := account
IMAGE := $(NAME)-service# Build image
build-debug:
# Clean unusing images (With the line only you need)
docker image prune -f# Build dlv for Linux
GOOS=linux GOARCH=amd64 go build github.com/go-delve/delve/cmd/dlv# Build program for Linux
GOOS=linux GOARCH=amd64 go build -gcflags "all=-N -l"# Build Docker image with certain Dockerfile
docker build -f Dockerfile.debug -t $(IMAGE) .# Clean the compiled files built just moment
rm -f $(NAME) dlv# Run container
run-debug:
# my-docker-network is My docker network for the micro-services
docker run --rm --name $(IMAGE) \
--network my-docker-network \
--security-opt="seccomp=unconfined" --cap-add=SYS_PTRACE \
-p 20000:20000 \
$(IMAGE)debug: build-debug run-debug
2. Configure Dockerfile.debug
The Docker ENTRYPOINT is ./dlv --listen=:20000 --headless=true --api-version=2 --log=true exec ./account
./
represents the WORKDIR (/app
),dlv
andaccount
were in it.--listen=:20000
The port for dlv server binding--headless=true
Just debug server, without UI--api-version=2
The version of dlv server’s API--log=true
Open dlv server’s log output, or only application’sexec ./account
Execute application for Debug
FROM alpine:3.9# For supporting https request
RUN apk add ca-certificatesRUN mkdir /app
WORKDIR /appADD dlv account config.yml ./ENTRYPOINT ["./dlv", "--listen=:20000", "--headless=true", "--api-version=2", "--log=true", "exec", "./account"]
3. Run Container
You will find that no any log of application’s. Because the dlv server only prepare to debug, then waiting the debug request from client, such as vscode.
$ make debug...2019-05-08T13:03:23Z info layer=debugger launching process with args: [./account]API server listening at: [::]:20000
Vscode Configuration and Break point
1. Create config section for launch debug
mode
Set to remote modelhost port
Set to dlv server addressprogram
Set to the main GoLang file of the application
launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Remote Debug",
"type": "go",
"request": "launch",
"mode": "remote",
"remotePath": "",
"port": 10001,
"host": "127.0.0.1",
"program": "${workspaceRoot}/cmd/account/main.go",
"showLog": true,
"env": {},
"args": []
}
]
}
2. Click Run Debug
, you will find the server print new messages is from application’s starting up.
3. Then create a break point in your code line. The dlv server will print:
2019–05–08T13:06:03Z debug layer=debugger halting
2019–05–08T13:06:03Z info layer=debugger created breakpoint: …
2019–05–08T13:06:03Z debug layer=debugger continuing
4. The next, you can debug your application just as in a local machine.