Realize から Air に移行し、 Go(echo) + Air + docker-compose でホットリロードを利用して開発を行う。

この記事は Go 2 Advent Calendar 2020 の4日目の記事です。

tl;dr

  • Goでホットリロード(a.k.a Live reload)を利用する際には今までは Realize というライブラリを使っている人が多いが、開発が止まっている。
  • 代わりに Air というライブラリを利用してホットリロードを行う。

Go + docker-composeを利用してホットリロードを利用した開発を行いたいと検索をして一番多かったのがrealizeというライブラリだった。

github.com

が、開発が停滞しているようで、issueも溜まっており、go modの対応もされておらず、2020/10/25 現在の環境で新規に作ろうとすると、いくつもハマる点があった。

他にライブラリは無いかといくつか調べたところ、Airというライブラリが開発も頻繁にされており、star数も多く筋が良さそうだったので、こちらを利用することにした。

github.com

利用方法

github.com

Usageにもあるが、

  1. .air.toml ファイルを作成する
  2. repositoryの.air_example.toml をコピーペーストし、自分の環境に合わせる
  3. コマンドを実行する air

.air.tomlの設定について

repositoryにexampleがあるので、それを参考にする。

air/air_example.toml at 71d8bf298b426e631c7f51947e8d706246b4ff16 · cosmtrek/air · GitHub

設定ファイルもそんなに難しくなく、ある程度はわかると思う。特に重要な点は

  1. cmd
  2. bin

cmd は自分のGo Appをbuildするコマンドを記述する。 bincmd でbuildしたbinaryのpathを記述する

実際に利用するシーンを見たほうが早いので、GitHubにpushしたコードを参考に構築する。

github.com

ディレクトリ構成は下記

$ tree -I frontend
.
├── LICENSE
├── README.md
├── backend
│   ├── Dockerfile
│   ├── cmd
│   │   └── app
│   │       └── main.go
│   ├── go.mod
│   ├── go.sum
│   ├── handlers
│   │   ├── handler.go
│   │   ├── root.go
│   │   └── routes.go
│   ├── models
│   └── repositories
└── docker-compose.yml

6 directories, 10 files

実際にホットリロードを行う。今回の場合の.air.tomlの構成は下記

go-next.js-playground/.air.toml at 0aaad99873a2b42821912c9d2c96cfa1260d8eaf · teitei-tk/go-next.js-playground · GitHub

$ cd backend/
$ go get -u github.com/cosmtrek/air
$ air -c .air.toml

  __    _   ___
 / /\  | | | |_)
/_/--\ |_| |_| \_ v1.12.1 // live reload for Go apps, with Go1.14.0

watching .
watching cmd
watching cmd/app
watching handlers
watching models
watching repositories
!exclude tmp
building...
running...

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.1.16
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:5000

$ curl localhost:5000
{"result":true}

handlers/root.go に手を入れてみる。

$ air -c .air.toml

  __    _   ___
 / /\  | | | |_)
/_/--\ |_| |_| \_ v1.12.1 // live reload for Go apps, with Go1.14.0

watching .
watching cmd
watching cmd/app
watching handlers
watching models
watching repositories
!exclude tmp
building...
running...

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.1.16
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:5000
handlers/root.go has changed
building...
running...

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.1.16
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:5000
$ $ curl localhost:5000
{"result":false}

JSON Responseが変わっていることがわかる。

docker-compose

ここまではローカル環境で行ってきたが、目的としてContainer上で行いたいのでdocker-composeで行ってみる。

Dockerfile

docker-compose.yml

$ docker-compose build api
Building api
Step 1/7 : FROM golang:1.15-alpine as base
 ---> b3bc898ad092
Step 2/7 : WORKDIR /app/go/base
 ---> Using cache
 ---> 99b11653d662
Step 3/7 : COPY go.mod .
 ---> 8d6ca0f99b03
Step 4/7 : COPY go.sum .
 ---> 72e5d889c991
Step 5/7 : RUN go mod download
 ---> Running in 5b61f9b803ee
Removing intermediate container 5b61f9b803ee
 ---> 05068d1b4923
Step 6/7 : RUN go get -u github.com/cosmtrek/air
 ---> Running in dbefc40ddd77
go: downloading github.com/cosmtrek/air v1.21.2
go: github.com/cosmtrek/air upgrade => v1.21.2
go: downloading github.com/fsnotify/fsnotify v1.4.9
go: downloading github.com/creack/pty v1.1.9
go: downloading github.com/imdario/mergo v0.3.8
go: downloading github.com/pelletier/go-toml v1.6.0
go: downloading github.com/fatih/color v1.7.0
go: github.com/pelletier/go-toml upgrade => v1.8.1
go: github.com/mattn/go-colorable upgrade => v0.1.8
go: github.com/mattn/go-isatty upgrade => v0.0.12
go: github.com/imdario/mergo upgrade => v0.3.11
go: github.com/fatih/color upgrade => v1.9.0
go: github.com/creack/pty upgrade => v1.1.11
go: golang.org/x/sys upgrade => v0.0.0-20201022201747-fb209a7c41cd
go: downloading github.com/fatih/color v1.9.0
go: downloading github.com/imdario/mergo v0.3.11
go: downloading github.com/creack/pty v1.1.11
go: downloading golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd
go: downloading github.com/pelletier/go-toml v1.8.1
go: downloading github.com/mattn/go-colorable v0.1.8
Removing intermediate container dbefc40ddd77
 ---> 7a9749558df6
Step 7/7 : COPY . .
 ---> 37c82f03a414

Successfully built 37c82f03a414
Successfully tagged go-nextjs-playground_api:latest

$ docker-compose up api
Recreating go-nextjs-playground_api_1 ... done
Attaching to go-nextjs-playground_api_1
api_1    |
api_1    |   __    _   ___
api_1    |  / /\  | | | |_)
api_1    | /_/--\ |_| |_| \_ v1.12.1 // live reload for Go apps, with Go1.14.0
api_1    |
api_1    | mkdir /app/go/base/tmp
api_1    | watching .
api_1    | watching cmd
api_1    | watching cmd/app
api_1    | watching handlers
api_1    | watching models
api_1    | watching repositories
api_1    | !exclude tmp
api_1    | building...
api_1    | running...
api_1    |
api_1    |    ____    __
api_1    |   / __/___/ /  ___
api_1    |  / _// __/ _ \/ _ \
api_1    | /___/\__/_//_/\___/ v4.1.16
api_1    | High performance, minimalist Go web framework
api_1    | https://echo.labstack.com
api_1    | ____________________________________O/_______
api_1    |                                     O\
api_1    | ⇨ http server started on [::]:5000
$ curl localhost:5000
{"result":true}

また handler/root.go のコードを変える。今回はJSON Responseの値をtrueからfalseに変更する。

api_1    | handlers/root.go has changed
api_1    | building...
api_1    | running...
api_1    |
api_1    |    ____    __
api_1    |   / __/___/ /  ___
api_1    |  / _// __/ _ \/ _ \
api_1    | /___/\__/_//_/\___/ v4.1.16
api_1    | High performance, minimalist Go web framework
api_1    | https://echo.labstack.com
api_1    | ____________________________________O/_______
api_1    |                                     O\
api_1    | ⇨ http server started on [::]:5000
$ curl localhost:5000
{"result":false}

Containerを起動したまま、レスポンスが変わっていること(ホットリロードされていること)がわかる。

まとめ

  • Realizeは開発が停滞しており、今後扱うと負債になる可能性が高い。
  • 代わりにAirというライブラリを利用することで、ホットリロード (a.k.a ライブロード) を利用することが出来るのでそちらを利用する。

ref

参考Project

github.com

各種PR

github.com

github.com