DockerでGo(echo)のライブリロード環境を作った
前までは、ホスト環境にGoをインストールして、echoを試していたのですが、Dockerでやる場合の環境を作ってみようと思ってやってみました。
今回作る環境としては、echo の動作する環境としていますが、echo のインストールはコンテナ立ち上げ後に一度だけ実行する予定なので書いていません。なので、Ginなどの他のフレームワークでも使える方法なんじゃないかと。試してはいませんが。
ディレクトリ構成
今回のプロジェクトのディレクトリ構成は以下です。
├── docker
│ ├── go
│ └── Dockerfile
├── docker-compose.yml
├── go.mod
├── go.sum
├── server.go
└── src
Go modules を使って依存管理をおこなっています。
また、docker-compose.yml を用意しているのは、今後MySQLなどのDBコンテナを立ち上げる予定をしているからです。
Goの環境を作る
docker/go/Dockerfile を用意します。
Go単体の実行環境を用意する
FROM golang:1.15.6-alpine
WORKDIR $GOPATH/src
RUN apk update && \
apk add --no-cache \
alpine-sdk \
git
ENV GO111MODULE=on # 一応明示的に有効にしておく
alpineベースのGoのイメージを元に構築しました。
musl-devパッケージが必要になりがちらしいのですが、なんだかんだgccを始めビルド用のパッケージが必要になるんじゃないかなーと思っているので、 alpine-sdk でまとめて入れちゃいました。
alpine-sdk - Alpine Linux packages
docker-compose.yml でまとめて動かせるようにしておく
後々、MySQLやRedisのような外部コンテナとの連携もしていくかもしれないので、docker-compose の設定をしておきます。
version: '3'
services:
app:
build:
context: .
dockerfile: docker/go/Dockerfile
tty: true
volumes:
- ./:/go/src
command: go run server.go
ports:
- 8080:8080
これでGoのコンテナをビルドして、server.go を走らせるまでできるようになりました。
server.go の中身は、Echoのドキュメントそのままです。(port指定だけ変えてます)
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":8080"))
}
Goの環境をライブリロード対応させる
ここまででGoのコンテナ起動時にサーバーが立ち上がるようになっていますが、コードを編集した際にコンテナ内の状態を更新してくれないので、ライブリロードさせるようにします。
※変更を検知してコンパイルしてくれる状態で、ブラウザの更新まではしません
ライブリロードの機能としては、 cosmtrek/air を使います。
cosmtrek/air: ☁️ Live reload for Go apps
これをDockerfileに追記します。アプリケーションには不要なので、位置としては go modules を有効にする前。
:
RUN go get -u github.com/cosmtrek/air
ENV GO111MODULE=on # 一応明示的に有効にしておく
これと .air.toml という設定ファイルが必要になります。
air_example.tomlの内容をベースに、cmd
のファイルパスのみ修正しました。
あとは、docker-compose.yml のcommand部分のみ変更します。
volumes:
- ./:/go/src
command: air
これによって、docker-composeでの起動時にairがgoファイルの変更を検知して自動でコンパイルをしてくれるようになりました。
やってみて
airの導入は結構楽だったので助かりました。
volumeの扱いやパッケージのインストールタイミングをどうするかの方が少し困ったくらいでした。