【Golang】Docker上でGin(+Air)を動かす（スタンダードなディレクトリ構成）

#はじめに
Docker上でGinを動かすまでの記事はありましたが、簡易的なディレクトリ構成での記事が多かったためスタンダードなディレクトリ構成で構築する手順をメモとして残しておこうと思います。
スタンダードなディレクトリ構成は下記記事を参考にさせていただきました。

https://github.com/golang-standards/project-layout/blob/master/README_ja.md

https://qiita.com/sueken/items/87093e5941bfbc09bea8


#ディレクトリ構成
今回は動作確認をするまでに使用したディレクトリのみ紹介します。

```
.
├──build
|   └──Dockerfile
├──cmd
|  └──#アプリ名
|     └──main.go
├──vendor
|   ​└──#[go mod vendor]で生成されるファイル群
├── web
|   └──templates
|       ​​​​└──index.html
​├──air.toml  #Airを使用したホットリロードの設定ファイル
├──docker-compose.yml
├──go.mod  #[go get github.com/gin-gonic/gin]でginはインストール済み
└──go.sum

```

# ファイル設定
Docker、Airのファイルの設定内容です。

```Dockerfile:build/Dockerfile
FROM golang:1.16.3-alpine

RUN apk add --update &&  apk add git
COPY go.mod /go/src/app/go.mod
COPY go.sum /go/src/app/go.sum
COPY vendor/ /go/src/app/vendor
WORKDIR /go/src/app
COPY . /go/src/app

RUN go get github.com/cosmtrek/air@v1.27.3

CMD ["air", "-c", ".air.toml"]**
```

```yml:docker-compose.yml
version: "3"
services: 
  app:
    container_name: "app"
    volumes:
      - .:/go/src/app
    tty: true 
    build:
      context: .
      dockerfile: build/Dockerfile
    ports:
      - "8080:8080"
```
  
`.air.toml`は下記の公式リポジトリから自分のディレクトリ構成に合わせて一部変更しています。

https://github.com/cosmtrek/air/blob/master/air_example.toml

```toml:.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]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/main ./cmd/#アプリ名/main.go" #ここを変更しています
# 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 = []
# 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"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # 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 # ms

[log]
# Show log time
time = 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
```

#動作確認(Hello World!するまで)
```go:cmd/アプリ名/main.go
package main

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

func main() {
	router := gin.Default()
	router.LoadHTMLGlob("web/templates/*.html")

	// Index
	router.GET("/", func(ctx *gin.Context) {
		ctx.HTML(200, "index.html", gin.H{})
	})
	router.Run()
}
```

```html:web/templates/index.html
<!DOCTYPE html>
<html lang="ja">

<head>
	<meta charset="UTF-8">
	<title>Sample App</title>
</head>

<body>
	<h1>Hello World!</h1>
</body>

</html>
```

ここまでコードを記述したら準備完了です。
コマンドで`docker-compose up -d --build`を実行します。

`localhost:8080`にアクセスして`Hello World!`できていることを確認してください。
また`index.html`の内容を変更して、`Air`を用いたホットリロードがうまく動作していることを確認してみてください。