Gin+Realize+docker-compose+Nginxで環境を整えてみる

Gin + Nginxで仕事でも使えるかな、と思いつつ開発環境を作成する

ソースは[こちら](https://github.com/ririkku/go-sandbox/tree/master/gin-nginx-sample)

# 環境
Go 1.14
Gin 1.5.0
Docker 19.03.8
docker-compose 1.25.4

# やること
1. GinでREST APIを作成
1. realizeでホットリロードできるようする
1. docker-composeでNginxを立ててリバプロする

# GinでREST APIを作成
GETでリクエストがきたら、 `{"key":"value"}`を返すだけのコードを作成

```main.go
package main

import "github.com/gin-gonic/gin"

func main() {
	router := gin.Default()

	router.GET("/api", func(context *gin.Context) {
		context.JSON(200,  gin.H{
			"key": "value",
		})
	})

	router.Run()
}
```

# realizeでホットリロードできるようする

変更後に`go run main.go`をするのが面倒なので、ホットリロードをできるようにする
realizeをInstallする

```.sh
go get github.com/oxequa/realize
```

main.goがあるディレクトリで

```
realize start
```
をすると、そのディレクトリに`.realize.yaml`が作成される

```..realize.yaml
settings:
  legacy:
    force: false
    interval: 0s
schema:
- name: src
  path: .
  commands: {}
  watcher:
    extensions:
    - go
    paths:
    - /
    ignored_paths:
    - .git
    - .realize
    - vendor
```

このままでは、watch状態にならないようなので、以下に変更する

```..realize.yaml
settings:
  legacy:
    force: false
    interval: 0s
schema:
- name: src
  path: .
  commands: 
    run:
      status: true
  watcher:
    extensions:
    - go
    paths:
    - /
    ignored_paths:
    - .git
    - .realize
    - vendor
```

そして再度実行すると、起動ログが出力される

```
realize start
```

```.go
[21:15:11][SRC] : Watching 1 file/s 1 folder/s
[21:15:11][SRC] : Install started
[21:15:12][SRC] : Install completed in 0.946 s
[21:15:12][SRC] : Running..
[21:15:12][SRC] : [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[21:15:12][SRC] : [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
[21:15:12][SRC] :  - using env: export GIN_MODE=release
[21:15:12][SRC] :  - using code:        gin.SetMode(gin.ReleaseMode)
[21:15:12][SRC] : [GIN-debug] GET    /api                      --> main.main.func1 (3 handlers)
[21:15:12][SRC] : [GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[21:15:12][SRC] : [GIN-debug] Listening and serving HTTP on localhost:8080
```

この状態で、コードの変更をすると変更を検知してリロードが走る

# Dockerリバプロの設定

localhost:80でリクエストがあると、Nginxが3000番ポートへ流す構成にする

## Gin環境のDockerfileとコードを少し改変

```Dockerfile
FROM golang:latest

RUN go get -u github.com/gin-gonic/gin && \
    go get -u github.com/oxequa/realize

WORKDIR /go/src/github.com/gin-nginx-sample/src

CMD [ "realize", "start"]
```

3000番ポートで起動するように変更
(一応ログファイルも出るようにして、リクエストIDを表示するだけのmiddlewareも書いてみた)

```main.go
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/labstack/gommon/log"
	"io"
	"os"
)

func main() {

	file, _ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(file)
	log.SetOutput(gin.DefaultWriter)

	router := gin.Default()

	router.GET("/api", myMiddleware(), func(context *gin.Context) {
		context.JSON(200, gin.H{
			"key": "value",
		})
	})

	router.Run(":3000")
}

func myMiddleware() gin.HandlerFunc {
	return func(context *gin.Context) {
		header := context.GetHeader("X-REQUEST-ID")
		log.Print("RequestId=" + header)
		context.Next()
	}
```

## Nginx環境のDockerfile

自分で書いた`nginx.conf`をnginx.confに上書きする

```
FROM nginx:latest

COPY ./nginx-docker/nginx.conf /etc/nginx/nginx.conf
```

```nginx.conf
worker_processes auto;

events {
    worker_connections  1024;
}

http {
    server {
         listen       80;
         location / {
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection "upgrade";
             proxy_set_header Host $host;

             proxy_pass http://golang:3000;
         }
    }
}
```

## docker-composeをかく

2つの`Dockerfile`を読み込んでdocker-composeを設定する

```docker-compose.yml
version: '3'
services:
  golang:
    container_name: "gin-nginx-sample"
    tty: true
    build:
      context: .
      dockerfile: ./go-docker/Dockerfile
    volumes:
      - ./src:/go/src/github.com/gin-nginx-sample/src
    ports:
      - "3000"

  nginx:
    container_name: "nginx"
    build:
      context: .
      dockerfile: ./nginx-docker/Dockerfile
    ports:
      - "80:80"
    depends_on:
      - "golang"
```

# 確認

1. `locahost:80/api`でアクセスしたら、`{"key":"value"}`が返ってる
1. `main.go`を変更して、ホットリロードが動く
これらができたら、成功！

# まとめ
普段意識して触ることのない技術スタックだったため、これだけの半日かかりました
もっと良い方法があったらぜひコメントください

# 参考
https://qiita.com/yoship1639/items/92405ab31779c8527c08