8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ニフティグループAdvent Calendar 2019

Day 16

[Go言語] freshでサブコマンドを扱う

Last updated at Posted at 2019-12-16

この記事は、ニフティグループ Advent Calendar 2019 16日目の記事です。
昨日は@Takumi-Miuraで「32bitUEFIのウルトラノートブックにubuntuをインストール」でした。
私も以前、windowsXPのpcにubuntuを入れて蘇らせた(かった)経験があります。古いOSのpcを持っている人は、Linuxを入れてしまうというのも一つの選択肢ですね。


はじめに

皆さんはGo言語で開発を行うときにどのような環境で開発を行っていますか?
私は、Docker+fresh(ホットリロード)で快適なGoライフを送っています!
しかし、このfresh・・・サブコマンドに対応しておりません
プルリクは出ていますがマージされず・・・。
image.png

今回は、非常にニッチな内容にはなりますが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です。

terminal
$ go version
go version go1.12.7 darwin/amd64

Go modulesを有効にします。

terminal
$ export GO111MODULE=on

モジュール管理ファイルを生成します。

terminal
$ go mod init .

実行するファイルを記述していきます。

main.go
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

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タグによって、サブコマンドを指定します。

docker-compose.yml
command: "gopher"

今回は、gopherniftyをそれぞれ実行します。

runner.conf(設定ファイル)

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     = ""

一部抜粋して説明します。

以下の記述で、実行するファイルが存在するディレクトリを指定します。

runner.conf
root = "."

プログラムの変更があった時に自動でビルドが走りますが、変更を監視するディレクトリを指定します。

runner.conf
watch_paths = []

生成されたバイナリファイルのディレクトを指定します。

runner.conf
output_binary = "."

監視対象にする拡張子を指定します。

runner.conf
valid_ext = [".go", ".tpl", ".tmpl", ".html"]

実行

必要なファイルが揃ったので実行していきます。

ビルドから。

terminal
$ docker-compose build
Building gopher-server
・・・
Successfully tagged fresh-subcommand_gopher-server:latest
Building nifty-server
・・・
Successfully tagged fresh-subcommand_nifty-server:latest

一部省略していますが、以上のようなメッセージが出力されれば成功です。

立ち上げます。

terminal
$ docker-compose up
・・・
gopher-server_1  | 8:29:44 main        | Waiting (loop 2)...
・・・
nifty-server_1   | 8:29:44 main        | Waiting (loop 2)...

別のターミナルで接続してみましょう。

terminal
$ curl http://localhost:8080
$ curl http://localhost:8081

立ち上げに成功していることが確認できました。

terminal
gopher-server_1  | 8:32:34 app         | Hello Gopher.
nifty-server_1   | 8:32:40 app         | Hello Nifty.

出力する文字列を変更してみましょう。

main.go
func helloGophers(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Hello Gopher!!!!")
}

func helloNifty(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Hello Nifty!!!!")
}

保存すると、自動でビルドが走ります。
数秒置いてから、再び確認してみましょう。

terminal
$ 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です。お楽しみに!

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?