Vscode debug GoLang micro-services in Docker

English @medium

查一般的 bug,我更習(xí)慣直接加打印,能快速定位問題,遠(yuǎn)比斷點調(diào)試方便的多。但遇到一些復(fù)雜、或是涉及第三方類庫時,卻不得不需要添加斷點逐步跟蹤邏輯。

使用 golang 開發(fā)的微服務(wù),全部是直接運行在 docker 容器里的,想要調(diào)試并不是一件簡單的事情,這時候我們就需要 Remote Debug (遠(yuǎn)程調(diào)試)

  • vscode - 代碼編輯器
  • ms-vscode.go - vscode 支持 Go 語言的插件
  • delve - Golang 調(diào)試工具,支持遠(yuǎn)程調(diào)試
  • Makefile - 封裝指令的合集
  • alpine - 迷你 Docker 系統(tǒng)鏡像,只有 5MB

啟動容器

通過MakefileDockerfile編譯鏡像和運行 Docker 容器,我的方式是在本地(MacOS)上編譯好 Linux 的可執(zhí)行文件,拷貝到用 alpine 小鏡像創(chuàng)建的容器里。也可以選擇用 golang 鏡像,拷貝源碼進(jìn)去。

  1. 配置 Makefile
  • 注意在編譯應(yīng)用程序時需要,通過添加 -gcflags "all=-N -l" 生成支持 Debug 的包
  • 運行容器時需要通過參數(shù) --security-opt="seccomp=unconfined" --cap-add=SYS_PTRACE 關(guān)閉容器的安全限制
  • 運行時需要把 dlv 監(jiān)聽的端口暴露出來 -p 20000:20000,以便 vscode 調(diào)試程序去連接
NAME := account
IMAGE := $(NAME)-service

# 編譯鏡像
build-debug:
    # 清理廢棄的image (按需開啟)
    docker image prune -f

    # 編譯Linux版 dlv可執(zhí)行文件
    GOOS=linux GOARCH=amd64 go build github.com/go-delve/delve/cmd/dlv

    # 編譯Linux版 應(yīng)用可執(zhí)行文件
    GOOS=linux GOARCH=amd64 go build -gcflags "all=-N -l"

    # 指定Dockerfile 生成鏡像
    docker build -f Dockerfile.debug -t $(IMAGE) .

    # 清理掉生成的可執(zhí)行文件
    rm -f $(NAME) dlv

# 運行容器
run-debug:
    # my-docker-network 是我的Docker network,所有的微服務(wù)都在這個網(wǎng)絡(luò)里,可以直接互連
    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
  1. 配置 Dockerfile.debug

容器啟動入口為 ./dlv --listen=:20000 --headless=true --api-version=2 --log=true exec ./account

  • ./代表 WORKDIR 的/app目錄,dlv、account 可執(zhí)行文件我們通過 Dockerfile 都已經(jīng)添加到這個目錄里了
  • --listen=:20000 dlv 服務(wù)綁定的端口
  • --headless=true 調(diào)試服務(wù)器,無 ui 模式
  • --api-version=2 服務(wù)提供的 API 版本
  • --log=true 開啟日志,否則只能看到應(yīng)用日志,沒有 dlv 自身的日志
  • exec ./account 準(zhǔn)備執(zhí)行的程序,這個程序必須支持 Debug

exec對應(yīng)的還有另外一個指令: debug,直接調(diào)試源碼可以用

FROM alpine:3.9

# 應(yīng)用程序需要這個組件來支持請求HTTPS的網(wǎng)址
RUN apk add ca-certificates

RUN mkdir /app
WORKDIR /app

ADD dlv account config.yml ./

ENTRYPOINT ["./dlv", "--listen=:20000", "--headless=true", "--api-version=2", "--log=true", "exec", "./account"]
  1. 運行容器

會發(fā)現(xiàn)沒有應(yīng)用啟動日志,是因為微服務(wù)在此時還未被拉起,只是關(guān)聯(lián)好了

$ make debug
...
2019-05-08T13:03:23Z info layer=debugger launching process with args: [./account]
API server listening at: [::]:20000

Vscode 配置及斷點調(diào)試

  1. 配置啟動文件
  • mode remote 開啟遠(yuǎn)程模式

  • host、port 配置成 dlv 暴露出的服務(wù)器地址

  • program 配置成本地對應(yīng)的源碼 main 文件

  • 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": []
    }
  ]
}
  1. 點擊開始調(diào)試,應(yīng)用才開始運行,所以可以看出是 vscode 客戶端通知 dlv 服務(wù)器啟動應(yīng)用的
  2. 這時候我們在 vscode 里創(chuàng)建一個斷點,服務(wù)器會出現(xiàn)對應(yīng)的日志。
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
  1. 接下來就和在本地調(diào)試程序是一樣的了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容