使用VisualStudioCode在远程调试中Docker和Golang

首先

由于一直无法获取到关于在Docker中封装Golang环境时如何进行调试的信息,所以我决定总结一下。

验证环境

主机方
    • Windows10 + Boot2Docker + VisualStudioCode

 

    Sierra + Docker for Mac + VisualStudioCode
容器一方
    golang:onbuildを使用(執筆時点ではgolang 1.7)

关于Golang的调试器

由于在VisualStudioCode中使用Delve,因此我会使用Delve。在查看文档和问题时,发现还支持远程调试,甚至可能支持Docker,这是导火索。

关于Docker的远程调试

似乎可以进行远程调试,以此为基础为Golang写代码重写。
使用 Docker 进行实时调试。

准备的文件

$GOPATH/src/github.com/user文件夹中有以下文件:
– .vscode文件夹
– launch.json文件
– docker-compose.yml文件
– Dockerfile文件
– main.go文件

// main.go
package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/garyburd/redigo/redis"
)

func main() {
    redi, err := redis.Dial("tcp", "redis:6379")
    if err != nil {
        log.Fatal(err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        res, err := redi.Do("incr", "counter")
        if err != nil {
            w.WriteHeader(500)
            w.Write([]byte(err.Error()))
            return
        }

        if res, ok := res.(int64); ok {
            w.Write([]byte(fmt.Sprintf("counter: %d", res)))
        } else {
            w.WriteHeader(500)
            w.Write([]byte("unexpected value"))
        }
    })
    log.Fatal(http.ListenAndServe(":5000", nil))
}
# Dockerfile
FROM golang:onbuild
RUN go get github.com/derekparker/delve/cmd/dlv
# docker-compose.yml
app:
  build: .
  ports:
    - "5000:5000" #golang webserver用のポート
    - "5050:5050" #delve用のポート
  links:
    - redis
  volumes:
    - ".:/go/src/app"
  privileged: true # Delveで必要なので付与します。セキュリティ面から本番環境では使うべきではありません。 
  command: dlv debug --headless --listen=:5050 --log 

redis:
  image: redis
{
    "version": "0.2.0",
    "configurations": [
         {
            "name": "Remote",
            "type": "go",
            "request": "launch",
            "mode": "remote",
            "remotePath": "/go/src/app", //コンテナ内のパス
            "port": 5050, // dlv debugのポートを指定(WEBのポートではない)
            "host": "192.168.99.100", //左の設定はToolBoxを使った場合のDocker MachineのIP. for Macの場合はlocalhostでよかった.
            "program": "${workspaceRoot}", //${workspaceRoot} = $GOPATH/src/github.com/user
            "env": {},
            "args": [],
            "showLog": true
        }
    ]
}

主要的.go文件是参考了这篇文章。
使用Redis来递增和显示数字的简单处理。
参考:使用Docker构建的Golang开发环境。

进行远程调试

启动容器

在main.go的当前位置构建并启动容器。

> docker-compose build
redis uses an image, skipping
Building app
Step 1 : FROM golang:onbuild
# Executing 3 build triggers...
Step 1 : COPY . /go/src/app
Step 1 : RUN go-wrapper download
 ---> Running in ff0ae2dae819
+ exec go get -v -d
github.com/garyburd/redigo (download)
Step 1 : RUN go-wrapper install
 ---> Running in d778a728a336
+ exec go install -v
github.com/garyburd/redigo/internal
github.com/garyburd/redigo/redis
app
 ---> 0b0ffd816054
Removing intermediate container ff0ae2dae819
Removing intermediate container d778a728a336
Removing intermediate container 677062574a96
Step 2 : RUN go get github.com/pilu/fresh
 ---> Running in 06b38d625b20
 ---> 3bc412d615be
Removing intermediate container 06b38d625b20
Step 3 : RUN go get github.com/derekparker/delve/cmd/dlv
 ---> Running in 10b51b638607
 ---> 206e4fb5f2c0
Removing intermediate container 10b51b638607
Successfully built 206e4fb5f2c0
> docker-compose up -d
> docker-compose ps
      Name                    Command               State                       Ports

----------------------------------------------------------------------------------------------------------
user_app_1     dlv debug --headless --lis ...   Up      0.0.0.0:5000->5000/tcp, 0.0.0.0:5050->5050/tcp
user_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp

只要有两个容器站起来就可以了。

用VisualStudioCode开始调试

听说,你可以使用VisualStudioCode从容器中启动代码。
首先,打开VisualStudioCode的调试视图,并在想要设置断点的代码处设置断点。

image

然后将左上方的调试切换到远程并运行。
※若成功,下方的状态栏将变为橙色。

image

当达到这种状态时,将启动容器内的main.go并在浏览器中打开IP地址进行访问(应该可以使用docker-machine的IP地址或localhost)。
将在设置断点的位置处触发断点。

image

除了常规的调试之外,您可以按照自己的喜好进行调试。

未能解决的问题

尽管我们已经可以进行远程调试,但仍然存在以下问题,使用仍然不够方便。

    1. 在执行过程中无法更改断点

 

    1. 在停止远程调试后重新执行会导致调试器挂起

 

    需要将Docker的privileged设置为True,这是不可取的。

1. 对于问题 1 ,如果进行重新启动或热部署的话,应该是可行的。
2. 对于问题 2,在 VSCode 中停止后无法开始新的远程调试,最终需要重新启动容器。(容器内残留的进程似乎是个问题,无法进行杀掉。)
3. 对于问题 3,不清楚 Delve 需要哪些权限,目前已经提供了全部权限,但从安全的角度来看并不好。可能需要采取只针对开发环境的对策。

有没有什么好的方法呢?

最后

我希望能够建立起利用VisualStudioCode和Golang的高度兼容性,既能作为编辑器使用,又能像集成开发环境一样使用,非常易用。
同时,我还想通过使用Docker来确立一种开发方法,以提高效率。

bannerAds