Golang
で Webサイトを作ろうと gin を触っていると、ライブリロードの機能がなく、変更が即座に反映されなくて、面倒くさく思っていました。
Air
というツールがよく使われていそうだったので、使ってみました。
このエントリはそのときのメモです。
gin アプリケーションの準備
まず、Air
と関係のない部分で最小のアプリケーションを用意します。
Golang
バージョンは以下の通りで、環境は macOS Catalina (10.15.7)
です。
$ go version go version go1.15.5 darwin/amd64
目指すフォルダ構成は以下です。
. ├── go.mod ├── go.sum └── main.go
フォルダを作成し、go modules
で環境を構築します。
$ mkdir gin-air-example && cd $_ $ go mod init gin-air-example go: creating new go.mod: module gin-air-example $ touch main.go
main.go
の内容は以下とします。
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "OK", }) }) r.Run(":3000") }
localhost:3000
にアクセスしたら、 {"message": "OK"}
というJSONを返します。
$ go run main.go go: finding module for package github.com/gin-gonic/gin go: found github.com/gin-gonic/gin in github.com/gin-gonic/gin v1.6.3 [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET / --> main.main.func1 (3 handlers) [GIN-debug] Listening and serving HTTP on :3000
$ curl localhost:3000 {"message":"OK"}
このように、デバッグのログにもアクセスが来たことが表示されます。
main.go を編集する
ここで、main.go
を以下のように変更します。
// (省略) func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ - "message": "OK", + "message": "Hello World", }) }) r.Run(":3000") }
main.go
を保存して、再度 localhost:3000
にアクセスしても結果は変わりません。
この際、go run main.go
を一旦止め、再度同じコマンドを実行すると出力結果は変わります。
$ curl localhost:3000 {"message":"Hello World"}
しかし、普段開発していて毎回 コマンドを叩き直すのはやめたいです。ここで Air
というツールを導入します。
Air を導入する
Air
を installします。
$ go get -u github.com/cosmtrek/air
.air.toml
ファイルを作成して、設定ファイルを公式の例)からコピーし、ペーストします。
# 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/main ." # Binary file yields from `cmd`. bin = "tmp/main" # Customize binary. full_bin = "APP_ENV=dev APP_USER=air ./tmp/main" # 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 = [] # Exclude unchanged files. exclude_unchanged = true # 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
そして、gin のプロセスを止め、airコマンドからWebアプリケーションを起動します。
$ air -c .air.toml
すると、main.go
への 変更が即座に反映されるようになったのがわかるかと思います。
これで Air
が導入できました。
gin アプリケーションの構築以外でやったことは、以下のみなので、簡単です。
Abr
の インストール- 設定ファイルの追加
必要に応じて、.air.toml
を修正して利用します。
最終的にファイル構成はこうなっています。
. ├── .air.toml ├── go.mod ├── go.sum └── main.go
Docker で利用
Docker
で利用する場合のメモも載せておきます。
Dockerfile
を作成
FROM golang:latest COPY ./ /go/app WORKDIR /go/app/ RUN go get -u github.com/gin-gonic/gin RUN go get -u github.com/cosmtrek/air CMD ["air", "-c", ".air.toml"]**
docker-compose.yml
を作成
version: '3' services: app: container_name: app build: context: ./ dockerfile: ./Dockerfile ports: - 3000:3000 tty: true volumes: - ./:/go/app
アプリケーションを立ち上げます。
$ docker-compose up —build Building app Step 1/6 : FROM golang:latest # 省略 Successfully built 6e9649de9e6b Successfully tagged gin-air-example_app:latest Recreating app ... done Attaching to app app | app | __ _ ___ app | / /\ | | | |_) app | /_/--\ |_| |_| \_ v1.12.1 // live reload for Go apps, with Go1.14.0 app | app | mkdir /go/app/tmp app | watching . app | !exclude tmp app | building... app | running... app | [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. app | app | [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. app | - using env: export GIN_MODE=release app | - using code: gin.SetMode(gin.ReleaseMode) app | app | [GIN-debug] GET / --> main.main.func1 (3 handlers) app | [GIN-debug] Listening and serving HTTP on :3000
2回目移行は --build
オプションは不要です。
これで同様にmain.go
の変更が即座に反映されるようになります。
最終のファイル構成はこちらです。
. ├── .air.toml ├── Dockerfile ├── docker-compose.yml ├── go.mod ├── go.sum └── main.go
終わりです。