🐳
dockerでgoのホットリロード環境を爆速で構築する
はじめに
はじめまして、otot_devです。
Go を業務で触ることになったので、手始めに個人で開発環境の構築を行ないながらアウトプットします。今回は、爆速でやるので開発効率的に絶対に必要なホットリロード部分をまずは構築します。
最終的なアウトプット
今回のコード一式は以下の URL にあります。
go-docker-template(v1.0.0)
バージョン情報
-
go
:v1.23.5 -
air-verse/air
:v1.61.7
※どちらもDockerfile
上は latest でインストールします。そのため、執筆時点ではうまくいきましたが、もしもうまくいかない場合はバージョン固定で利用してみてください。
構築編
air-verse/air の README
今回は、docker でホットリロード環境を構築したいので、air-verse/air 公式の README を見ます。
途中の見出しにDockerfile
、docker-compose.yaml
があるのでこちらを参考にしました。
Dockerfile
容量が気になる人はおとなしくFROM golang:1.23-alpine
で軽量なものを使用した方が良いかもしれません。
go-docker-template(v1.1.0)ではやはり軽量なものに変更しました。
# v1.23.5
- FROM golang:latest
+ FROM golang:1.23-alpine
WORKDIR /app
# v1.61.7
RUN go install github.com/air-verse/air@latest
COPY go.mod go.sum ./
RUN go mod download
CMD ["air", "-c", ".air.toml"]
docker-compose.yml
services:
api:
build:
context: .
dockerfile: Dockerfile
ports:
- 8080:3000
volumes:
- ./:/app
.air.toml
air の設定ファイル。公式のほぼそのままにしてます。
# Config file for [Air](https://github.com/air-verse/air) in TOML format
# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"
[build]
# Array of commands to run before each build
pre_cmd = []
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/main ."
# Array of commands to run after ^C
post_cmd = []
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary, can setup environment variables when run your app.
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
# Add additional arguments when running binary (bin/full_bin). Will run './tmp/main hello world'.
args_bin = ["hello", "world"]
# 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 = []
# Watch these files.
include_file = []
# Exclude files.
exclude_file = []
# Exclude specific regular expressions.
exclude_regex = ["_test\\.go"]
# Exclude unchanged files.
exclude_unchanged = true
# Follow symlink for directories
follow_symlink = true
# This log file is placed in your tmp_dir.
log = "air.log"
# Poll files for changes instead of using fsnotify.
poll = false
# Poll interval (defaults to the minimum interval of 500ms).
poll_interval = 500 # ms
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 0 # 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 # nanosecond
# Rerun binary or not
rerun = false
# Delay after each execution
rerun_delay = 500
[log]
# Show log time
time = false
# Only show main log (silences watcher, build, runner)
main_only = false
# silence all logs produced by air
silent = 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
[screen]
clear_on_rebuild = true
keep_scroll = true
[proxy]
# Enable live-reloading on the browser.
enabled = true
proxy_port = 8090
app_port = 3000
go.mod
go のバージョンを指定してます。
module go-docker-template
go 1.23.5
go.sum
本来は依存関係が細かく記録されたファイルなんですが、空の状態で構わないのでファイルだけ作成してます。
main.go
go の実行ファイル。
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
})
log.Fatal(http.ListenAndServe(":3000", nil))
}
実行編
docker compose up
で以下のようなログが出力されたらサーバーは起動してます。
% docker compose up
[+] Running 1/0
✔ Container go-docker-template-api-1 Created 0.0s
Attaching to api-1
api-1 |
api-1 | __ _ ___
api-1 | / /\ | | | |_)
api-1 | /_/--\ |_| |_| \_ v1.61.7, built with Go go1.23.5
api-1 |
api-1 | mkdir /app/tmp
api-1 | watching .
api-1 | !exclude tmp
api-1 | Proxy server listening on http://localhost:8090
api-1 | building...
api-1 | running...
ホットリロードの確認
- 以下でコンソールログが出力されるか確認。
% curl localhost:8080
Hello, World!
- main.go を更新
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "Hello, World!")
+ fmt.Fprintf(w, "Great!")
})
- コンソールログの出力が変わるか確認。
% curl localhost:8080
Great!
ホットリロードができていることが確認できました。
Discussion