Help us understand the problem. What is going on with this article?

Docker上のGo製Webアプリケーションをリモートデバッグする

概要

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の内容

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/dlvgo build -o /go/bin/dlv github.com/go-delve/delve/cmd/dlv の部分が重要になります。

delve というGoLang用のDebuggerをインストールしています。

開発時にホットリロードを有効にしたいので go get -u github.com/cosmtrek/aircosmtrek/air をインストールしています。

docker-composeの設定

以下のように設定します。

docker-compose.yml
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

commandair を起動させています。

ports8888(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の設定

下記の通りです。

air.conf
# 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... から設定を作成します。

createDebug1.png

この記事の通りにやれば delve での利用ポートはデフォルトの2345なので Go Remote のTemplateを使って作成すれば良いです。

createDebug2.png

Name はこの記事では app としていますが、わかり易ければ何でも構いません。

GoLand側からDockerコンテナに接続する

Run → Debug → から先程作成したデバッグ設定を開きます。

ConnectRemoteServer1.png

下記のように表示されていれば、接続が完了しています。

ConnectRemoteServer2.png

ちなみに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にアクセスしましょう。

ブレークポイントでアプリケーションが一時停止し変数の中身等が確認出来るかと思います。

ConnectRemoteServer3.png

※ アプリケーションのコードを修正した場合、GoLand側でDebuggerとのコネクションを再接続する必要があります。

ReDebug.png

あとがき

ここまでのコードはGitHubに公開してあります。

https://github.com/nekochans/portfolio-backend

Debuggerが使えると開発効率が上がりますので、少々時間をかけてでも設定を行うことをオススメします。

以上になります。最後まで読んで頂きありがとうございます。

keitakn
フリーランスのWeb系エンジニア、 フロントエンド、バックエンド両方やります。🐱好きです🐱
https://github.com/keitakn/cv
readyfor
想いをつなぎ、叶える未来を、つくる READYFORのOrganizationです
https://tech.readyfor.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away