概要
Docker上で動作するGo製Webアプリケーションをデバッグする方法を解説します。
2020-05-03 追記
以前は oxequa/realize
を利用していましたが、 2020年5月3日現在 oxequa/realize
はメンテナンスが止まっています。
例えば 去年私が追加したissue は閉じられていませんし、その他のPRもマージされていません。
その為 cosmtrek/air を使った形に記事を大幅に書き換えました。
cosmtrek/air はメンテナンスが継続されており、GoModuleにも対応しているので、oxequa/realize
の代わりは十分に果たせると思っています。
環境
- ホストOS(macOS Catalina バージョン 10.15.4)
- GoLand 2020.1.1
- Docker Desktop for Mac(Docker version 19.03.8)
- 利用するDockerイメージ(golang:1.14-alpine3.11)
この記事ではホストPC上で利用するツールとしてGoLandを利用しますが、Visual Studio Code 等でも同じことは実現出来ると思います。
Docker側の設定
Dockerfileの内容
FROM golang:1.14-alpine3.11 as build
LABEL maintainer="https://github.com/nekochans"
WORKDIR /go/app
COPY . .
ENV GO111MODULE=off
RUN set -eux && \
apk update && \
apk add --no-cache git curl && \
go get -u github.com/cosmtrek/air && \
go build -o /go/bin/air github.com/cosmtrek/air && \
go get -u github.com/go-delve/delve/cmd/dlv && \
go build -o /go/bin/dlv github.com/go-delve/delve/cmd/dlv
ENV GO111MODULE on
RUN set -eux && \
go build -o portfolio-backend ./cmd/rest/main.go
FROM alpine:3.11
WORKDIR /app
COPY --from=build /go/app/portfolio-backend .
RUN set -x && \
addgroup go && \
adduser -D -G go go && \
chown -R go:go /app/portfolio-backend
CMD ["./portfolio-backend"]
go get -u github.com/go-delve/delve/cmd/dlv
と go build -o /go/bin/dlv github.com/go-delve/delve/cmd/dlv
の部分が重要になります。
delve
というGoLang用のDebuggerをインストールしています。
開発時にホットリロードを有効にしたいので go get -u github.com/cosmtrek/air
でcosmtrek/air をインストールしています。
docker-composeの設定
以下のように設定します。
version: '3.7'
services:
go:
build:
context: .
dockerfile: docker/go/Dockerfile
target: build
volumes:
- ./:/go/app
command: air
ports:
- 8888:8888
- 2345:2345
security_opt:
- apparmor:unconfined
cap_add:
- SYS_PTRACE
command
で air
を起動させています。
ports
で 8888
(WebServer用のポート)と 2345
(デバッグ用のポート)を開放します。
security_opt
, cap_add
の2つはDocker上で delve
を利用する為の設定です。
security_opt:
- apparmor:unconfined
Dockerが行うシステムコールを制限するオプションです。
(参考)https://docs.docker.com/engine/security/seccomp/
cap_add:
- SYS_PTRACE
コンテナの capabilities の追加を行います。
(参考)https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
(参考)Docker コンテナ上で Go のプロジェクトを delve でデバッグするには ptrace の許可が必要
airの設定
下記の通りです。
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"
[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o tmp/portfolio-backend ./cmd/rest/main.go"
# Binary file yields from `cmd`.
bin = "tmp/portfolio-backend"
# Customize binary.
full_bin = "APP_ENV=dev APP_USER=air /go/bin/dlv exec ./tmp/portfolio-backend --headless=true --listen=:2345 --api-version=2 --accept-multiclient"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
exclude_file = []
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms
[log]
# Show log time
time = false
[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"
[misc]
# Delete tmp directory on exit
clean_on_exit = true
重要なのは下記の部分です。
root = "."
tmp_dir = "tmp"
cmd = "go build -o tmp/portfolio-backend ./cmd/rest/main.go"
bin = "tmp/portfolio-backend"
full_bin = "APP_ENV=dev APP_USER=air /go/bin/dlv exec ./tmp/portfolio-backend --headless=true --listen=:2345 --api-version=2 --accept-multiclient"
ファイルの変更が行われる度に cmd
に設定されているBuildを実行し delve
を再読み込みします。
GoLand側の設定
GoLandデバッグのデバッグ設定を作成する
Run → Debug → 0. Edit Configurations...
から設定を作成します。
この記事の通りにやれば delve
での利用ポートはデフォルトの2345なので Go Remote
のTemplateを使って作成すれば良いです。
Name
はこの記事では app
としていますが、わかり易ければ何でも構いません。
GoLand側からDockerコンテナに接続する
Run → Debug →
から先程作成したデバッグ設定を開きます。
下記のように表示されていれば、接続が完了しています。
ちなみにDockerのログを見ると下記のようにアプリケーションの起動を確認出来るかと思います。
❯❯❯ docker logs -f bd1438fb171f
__ _ ___
/ /\ | | | |_)
/_/--\ |_| |_| \_ v1.12.1 // live reload for Go apps, with Go1.14.0
mkdir /go/app/tmp
watching .
watching _sql
watching application
watching cmd
watching cmd/rest
watching config
watching docker
watching docker/go
watching docker/mysql
watching docker/mysql/config
watching docker/nginx
watching docker/nginx/config
watching domain
watching infrastructure
watching infrastructure/repository
watching k8s
watching test
watching test/data
watching test/data/memberscenario
watching test/data/memberscenario/fetchallfrommysql
watching test/data/memberscenario/fetchallfrommysql/succeed
watching test/data/memberscenario/fetchfrommysql
watching test/data/memberscenario/fetchfrommysql/succeed
watching test/data/webservicescenario
watching test/data/webservicescenario/fetchallfrommysql
watching test/data/webservicescenario/fetchallfrommysql/succeed
!exclude tmp
building...
running...
API server listening at: [::]:2345
2020/05/03 06:54:28 env: develop
2020/05/03 06:54:28 Starting app
GoLandでブレークポイントを設定してデバッグ
ブレークポイントを設定してアプリケーションのURLにアクセスしましょう。
ブレークポイントでアプリケーションが一時停止し変数の中身等が確認出来るかと思います。
※ アプリケーションのコードを修正した場合、GoLand側でDebuggerとのコネクションを再接続する必要があります。
あとがき
ここまでのコードはGitHubに公開してあります。
Debuggerが使えると開発効率が上がりますので、少々時間をかけてでも設定を行うことをオススメします。
以上になります。最後まで読んで頂きありがとうございます。