Goでホットリロード可能なローカル開発環境をDockerとAirで構築する
記事の内容
ホットリロード(ファイルを変更すると自動で変更が反映される)可能なGoのローカル開発環境をAirとDockerで構築します。
記事を読むと得られるもの
- ホットリロードが可能なローカル開発環境の構築
- GoのDockerfileの作り方
- docker composeを使ったローカル開発方法
対象読者
- Go初心者
- これからGoで開発をする人
記事の長さ
3分で読めます
Go Projectを作成する
まずは、Goのプロジェクトを作成します。
Go Projectの初期化
$ mkdir go-project
$ cd go-project
$ go mod init my-app
go: creating new go.mod: module my-app
$ ls
go.mod
これで、Goのファイルを配置するgo-project
ディレクトリの準備ができました。
main.goの作成
次に、goのソースを書いていく、main.go
ファイルにWebサーバーを起動するGoプログラムを書いてきます。
$ touch main.go
main.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(":8080", nil))
}
上記ソースを実行すると、localhost:8080で起動するWebサーバーが立ち上がります。
$ go run main.go
$ curl localhost:8080
Hello, World!%
go run main.go
でWebサーバーを立ち上げて、curlコマンドで無事にアクセスできました!(curlコマンドを使用せずに、ブラウザから、http://localhost:8080にアクセスしても大丈夫です。)
以上で、Goのプロジェクトの初期構築は完了です。
プロジェクトフォルダの中は以下のようになっているはずです。
$ tree
.
├── go.mod
└── main.go
ローカル開発環境をDockerとAirで構築する
Goのプロジェクトが動作するDocker環境を構築していきます。
Dockerfileを作成する
Goが動作するDockerコンテナのベースとなるDockerfileを作成してきます。
Dockerfile
という名前のファイルを作成し、以下のように編集してください
Dockerfile
FROM golang:1.21.3
WORKDIR /app
RUN go install github.com/cosmtrek/air@latest
CMD ["air"]
docker-composeファイルを作成する
次に、先ほど作成したDockerfileを元に、docker-compose.ymlファイルを作成します。
docker-compose.yml
version: "3.9"
services:
go:
build: .
ports:
- "8080:8080"
volumes:
- .:/app
airの設定ファイルを追加する
最後に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]
# Array of commands to run before each build
pre_cmd = ["echo 'hello air' > pre_cmd.txt"]
# 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 = ["echo 'hello air' > post_cmd.txt"]
# 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"
# 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 places 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 executions
rerun_delay = 500
# Add additional arguments when running binary (bin/full_bin). Will run './tmp/main hello world'.
args_bin = ["hello", "world"]
[log]
# Show log time
time = false
# Only show main log (silences watcher, build, runner)
main_only = 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
※ Airの公式GithubのExampleのままです ( https://github.com/cosmtrek/air/blob/master/air_example.toml )
起動してみる
これで準備が完了しました。本記事の通りに、ファイルが作成できていたら、以下のようなディレクトリ構成になっているはずです。
$ tree -a
.
├── .air.toml
├── Dockerfile
├── docker-compose.yml
├── go.mod
├── main.go
docker compose up
コマンドを実行してください。
$ docker compose up
[+] Running 1/0
✔ Container go-project-go-1 Created 0.0s
Attaching to go-project-go-1
go-project-go-1 |
go-project-go-1 | __ _ ___
go-project-go-1 | / /\ | | | |_)
go-project-go-1 | /_/--\ |_| |_| \_ v1.49.0, built with Go go1.21.3
go-project-go-1 |
go-project-go-1 | mkdir /app/tmp
go-project-go-1 | watching .
go-project-go-1 | !exclude tmp
go-project-go-1 | > echo 'hello air' > pre_cmd.txt
go-project-go-1 | building...
go-project-go-1 | running...
Airを使って、GoのProjectが起動するのがわかります。
$ curl localhost:8080
Hello, World!%
curlコマンドでアクセスすると、正常に文字列が返却されます。
ファイル内容を変更してみる
次に、ホットリロードが正常に機能するかを確かめるため、Dockerが起動したままファイル内容を変更します。
main.go
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Good!")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
文字列をHell, World!
からGood!
に変更しました。このファイルを保存すると、自動でAirが変更内容をDockerコンテナに反映してくれます。
正常に反映されたか、curlコマンドで確かめます。
$ curl localhost:8080
Good!%
正常に変更されていることが確認できました!
Sample Source
今回使用したソースは、以下です!
note
勉強法やキャリア構築法など、エンジニアに役立つ記事をnoteで配信しています。
Discussion