この記事は、ニフティグループ Advent Calendar 2019 16日目の記事です。
昨日は@Takumi-Miuraで「32bitUEFIのウルトラノートブックにubuntuをインストール」でした。
私も以前、windowsXPのpcにubuntuを入れて蘇らせた(かった)経験があります。古いOSのpcを持っている人は、Linuxを入れてしまうというのも一つの選択肢ですね。
はじめに
皆さんはGo言語で開発を行うときにどのような環境で開発を行っていますか?
私は、Docker+fresh(ホットリロード)で快適なGoライフを送っています!
しかし、このfresh・・・サブコマンドに対応しておりません。
プルリクは出ていますがマージされず・・・。
今回は、非常にニッチな内容にはなりますがfreshでサブコマンドを使用する方法を調査したので情報を共有します。
なお、freshの基本的な使用方法や概要については、@po3rinさんのGo v1.11 + Docker + fresh でホットリロード開発環境を作って愉快なGo言語生活やREADME.mdが参考になるのでそちらをご参照ください。
本編
今回は、サブコマンドを利用して複数のサーバーを立ち上げ、それぞれの環境でホットリロードできるかを確認します。
解決方法
オリジナルをフォークして機能を拡張している方がいたので、そちらを使わせていただきます。
c2h5oh/fresh
構成
最終的な構成は以下のようになります。
.
├── Dockerfile
├── docker-compose.yml
├── go.mod
├── go.sum
├── main
├── main.go
├── runner.conf
└── tmp
└── hot_reload_docker
ローカルで試す
はじめに、ローカル環境で実行してみましょう。
まず、go modulesが使用できるバージョンであることを確認します。1.1以上ならOKです。
$ go version
go version go1.12.7 darwin/amd64
Go modulesを有効にします。
$ export GO111MODULE=on
モジュール管理ファイルを生成します。
$ go mod init .
実行するファイルを記述していきます。
package main
import (
"fmt"
"log"
"net/http"
"os"
"github.com/gorilla/mux"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "nifty gopher"
app.Usage = "Hello nifty gopher."
app.Version = "1.0.0"
app.Commands = []cli.Command{
{
Name: "gopher",
Usage: "Hello Gopher",
Action: func(c *cli.Context) {
router := mux.NewRouter()
router.HandleFunc("/", helloGophers).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", router))
},
}, {
Name: "nifty",
Usage: "Hello Nifty",
Action: func(c *cli.Context) {
router := mux.NewRouter()
router.HandleFunc("/", helloNifty).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", router))
},
},
}
app.Run(os.Args)
}
func helloGophers(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hello Gopher.")
}
func helloNifty(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hello Nifty.")
}
以上のコードで、サブコマンドに対応したサーバーが立ち上がります。
gopherサーバーから立ち上げます。
$ go build .
$ ./main gopher
別のターミナルから接続してみます。
$ curl http://localhost:8080
Hello Gopher.
と出力されれば成功です。
また、./main nifty
に置き換えて実行してみてください。
Hello Nifty.
と出力されれば、サブコマンドによってサーバーを指定できるcliツールの完成です。
Dockerのホットリロード環境で実行する
いよいよDockerのホットリロード環境で実行します。
必要なファイルを記述しましょう。
Dockerfile
FROM golang:1.13
WORKDIR /go/src/hot_reload_docker
COPY . .
ENV GO111MODULE=on
RUN go get github.com/c2h5oh/fresh
ENTRYPOINT ["fresh","-c","runner.conf","-r"]
重要な部分のみ説明します。
以下のコマンドでパッケージをダウンロードします。
今回は、フォークされたパッケージを利用します。
RUN go get github.com/c2h5oh/fresh
最後にfreshを利用して実行を行います。
ENTRYPOINT ["fresh","-c","runner.conf","-r"]
オプションについて説明します。
- -c・・・読み込む設定ファイルを記述します。設定ファイルについては後述します。
- -r・・・ビルドされたバイナリに渡されるサブコマンドを記述します。実際に指定するコマンドは、docker-compose.ymlの方に記述します。
他のオプションのについてはREADME.mdに記載されていますので、ご参照ください。
docker-compose.yml
version: '3'
services:
gopher-server:
build: .
volumes:
- ./:/go/src/hot_reload_docker
ports:
- "8080:8080"
command: "gopher"
nifty-server:
build: .
volumes:
- ./:/go/src/hot_reload_docker
ports:
- "8081:8080"
command: "nifty"
commandタグ
によって、サブコマンドを指定します。
command: "gopher"
今回は、gopher
、nifty
をそれぞれ実行します。
runner.conf(設定ファイル)
root = "."
watch_paths = []
exclude_paths = []
tmp_path = "./tmp"
output_binary = "."
build_log = "runner-build-errors.log"
valid_ext = [".go", ".tpl", ".tmpl", ".html"]
build_delay = 600
colors = true
log_color_main = "cyan"
log_color_build = "yellow"
log_color_runner = "green"
log_color_watcher = "magenta"
log_color_app = ""
一部抜粋して説明します。
以下の記述で、実行するファイルが存在するディレクトリを指定します。
root = "."
プログラムの変更があった時に自動でビルドが走りますが、変更を監視するディレクトリを指定します。
watch_paths = []
生成されたバイナリファイルのディレクトを指定します。
output_binary = "."
監視対象にする拡張子を指定します。
valid_ext = [".go", ".tpl", ".tmpl", ".html"]
実行
必要なファイルが揃ったので実行していきます。
ビルドから。
$ docker-compose build
Building gopher-server
・・・
Successfully tagged fresh-subcommand_gopher-server:latest
Building nifty-server
・・・
Successfully tagged fresh-subcommand_nifty-server:latest
一部省略していますが、以上のようなメッセージが出力されれば成功です。
立ち上げます。
$ docker-compose up
・・・
gopher-server_1 | 8:29:44 main | Waiting (loop 2)...
・・・
nifty-server_1 | 8:29:44 main | Waiting (loop 2)...
別のターミナルで接続してみましょう。
$ curl http://localhost:8080
$ curl http://localhost:8081
立ち上げに成功していることが確認できました。
gopher-server_1 | 8:32:34 app | Hello Gopher.
nifty-server_1 | 8:32:40 app | Hello Nifty.
出力する文字列を変更してみましょう。
func helloGophers(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hello Gopher!!!!")
}
func helloNifty(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hello Nifty!!!!")
}
保存すると、自動でビルドが走ります。
数秒置いてから、再び確認してみましょう。
$ curl http://localhost:8080
$ curl http://localhost:8081
出力が変更されていることが確認できました。
gopher-server_1 | 8:39:13 app | Hello Gopher!!!!
nifty-server_1 | 8:39:14 app | Hello Nifty!!!!
まとめ
今回は、freshでサブコマンドを使用する方法を紹介しました。
フォークされたリポジトリを利用するということは初めてでしたが、誰かが作ったものに対して機能を追加できるOSSはとても面白いですね。
これで、快適なGoライフを継続できそうです!
明日は@fuku710です。お楽しみに!