realize + dockerでGolangのホットリロード付き開発環境を構築する
今回は、gin + gqlgen + gormなGoプロジェクトのホットリロード付き開発環境を構築します。
環境
- Go 1.12.6
プロジェクトの構造
.
├── db
│ └── db.go
├── models
│ ├── model_a.go
│ └── ...
├── schema
│ ├── schema.graphql
│ └── ...
├── server
│ └── server.go
├── docker-compose.yml
├── go.mod
├── go.sum
├── gqlgen.yml
└── ...
使用するホットリロードツール
realizeというツールを使用します。
他にもfreshなどのホットリロードツールがありますが、realizeの方が設定が細かくできるため、realizeを選択しました。
実は最初、freshで試していたのですが、Go Modulesモードに対応できないっぽかったです。
realizeでは適切に設定を行うことで、対応可能となっていることがわかりました。
Dockerfileとdocker-compose.ymlの準備
以上を踏まえて、ホットリロードを行うためのDockerfileとdocker-compose.ymlを準備します。
FROM golang:1.12.6-alpine
WORKDIR /app
RUN apk add --no-cache alpine-sdk git && go get -u github.com/oxequa/realize
EXPOSE 8080
CMD ["realize", "start"]
docker-compose.ymlにて、開発環境のディレクトリをコンテナにアタッチする設定を行います。
そのため、ここではソースをコピーは行わず、WORKDIRと必要なパッケージのインストールのみ行います。
version: '3'
services:
db:
image: mysql:5.7
ports:
- "3306"
restart: always
command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
environment:
MYSQL_DATABASE: sample
MYSQL_ROOT_PASSWORD: password
volumes:
- mysql-data:/var/lib/mysql
application:
build: .
environment:
MYSQL_DATABASE: sample
MYSQL_HOST: db
MYSQL_PASSWORD: password
MYSQL_PORT: 3306
MYSQL_USER: root
depends_on:
- db
ports:
- "8095:8080"
restart: always
volumes:
- .:/app
volumes:
mysql-data:
driver: local
以下の部分で、開発環境のディレクトリをコンテナにアタッチする場所を選びます。
アタッチ先として、DockerfileのWORKDIRと同じ場所が設定されていることを確認します。
volumes:
- .:/app
realizeの設定
DockerfileのCMDにてrealize startを実行するようにしていますが、このコマンド単体ではアプリケーションが起動しません。
まずは手元でrealize startを実行します。
$ go get -u github.com/oxequa/realize
# $GOPATH/binにPATHを通っていることを確認した後
$ realize start
すると.realize.ymlという設定ファイルが生成されます。
適当なgoファイルを変更しセーブすると、その旨がログに出力されることを確認し、Ctrl+Cで実行を終了します。
settings:
legacy:
force: false
interval: 0s
schema:
- name: sample
path: .
commands: {}
watcher:
extensions:
- go
paths:
- /
ignore:
paths:
- .git
- .realize
- vendor
アプリケーションを起動するにはrealize start --runというふうに引数に--runを与えるか、.realize.ymlを以下のように修正します。
- commands: {}
+ commands:
+ run:
+ status: true
通常、この状態でrealize startするとアプリが立ち上がるのですが、Go Modulesモードである場合はエラーが発生して起動しません。
また、今回の場合はmain関数が定義されているファイルがmain.goではなく、server/server.goにあるため、その点も特殊です。
これを吸収するための設定を追加します。
commands:
+ install:
+ status: true
+ method: go build -o app.out ./server/server.go
run:
status: true
+ method: ./app.out
これでホットリロードが有効な状態で、アプリケーションが立ち上がるようになります。
手元でrealize startを実行し、挙動を確認しましょう。
realizeはデフォルトでプロジェクトをリビルドする際に$GOPATH/binにリビルドするためにgo installを使用します。
Go Modulesモードでは$GOPATHが存在しないので、go installに失敗してしまいます。
これを避けるため、go installではなく、go build -o app.out ./server/server.goを使用するように設定し、起動時はその成果物を利用して起動するようにしています。
docker-composeで起動
ここまでできれば後はdocker-composeで起動するだけです。
docker-compose build
docker-compose up -d
Discussion
Go 1.15.2ではなくgo1.12.6ではないでしょうか?👀
修正しました!ご指摘ありがとうございました!
どうやらかなり未来に生きてしまっていたようです・・・