Docker + Go + Gin の開発環境を準備する

本記事は2018年5月に公開されました。
Go Modules に対応した記事を再投稿しましたので、
そちらを参照ください。
[Docker + Go + Gin の開発環境を準備する 2020/02](https://qiita.com/kkeisuke/items/f2c814bb928c1f69c856)

---

Go + Gin で Web API を構築する際の開発環境を準備します。
Docker、Go ともに不慣れだったので、
まずは Gin の [クイックスタート](https://github.com/gin-gonic/gin#quick-start)が動作するところまでの備忘録です。

いつも環境を用意してくれていたチームメンバーに感謝です:sweat:

なお、macOS Sierra 上でのみ検証した結果です。

## 構成

- Docker：[Docker Community Edition for Mac](https://store.docker.com/editions/community/docker-ce-desktop-mac)
  - Docker version 18.03.1-ce, build 9ee9f40
  - docker-compose version 1.21.1, build 5a3f1a3
- イメージ：[golang By Docker](https://store.docker.com/images/golang)
- パッケージ管理：[dep](https://golang.github.io/dep/)
- ライブリロード：[codegangsta/gin](https://github.com/codegangsta/gin)
- Webフレームワーク：[gin-gonic/gin](https://github.com/gin-gonic/gin)

## ディレクトリ

後々 DB 用コンテナも作成する事を考慮したプロジェクト構成にしています。

```
.
├── .dockerignore
├── docker
│   └── api
│       └── Dockerfile
├── docker-compose.yml
└── src
    └── api
        ├── Gopkg.lock
        ├── Gopkg.toml
        └── main.go
```

## .dockerignore

- 参考
  - [.dockerignore アンチパターン](https://qiita.com/munisystem/items/b0f08b28e8cc26132212)

今のところ何も指定していません。

```.dockerignore:.dockerignore
Dockerfile*
```

## Dockerfile

- 参考
  - [Dockerfile リファレンス](http://docs.docker.jp/engine/reference/builder.html)

```Dockerfile:Dockerfile
# API Image 作成

# ベースとなるイメージ
FROM golang:1.10.2-alpine3.7

# Gopkg.toml 等を事前にコピーして dep ensure が実行できるようにする
COPY src/api /go/src/api/

# dep ensure を行うプロジェクトルートに移動する
WORKDIR /go/src/api/

# 必要なパッケージをイメージにインストールする
RUN apk update \
  && apk add --no-cache git \
  && go get -u github.com/codegangsta/gin \
  && go get -u github.com/golang/dep/cmd/dep \
  && dep ensure

# コンテナ実行時のデフォルトを設定する
# ライブリロードを実行する
CMD gin -i run
```

## docker-compose.yml

- 参考
  - [Compose ファイル・リファレンス](http://docs.docker.jp/compose/compose-file.html)
  - [DockerでVolumeをマウントするとき一部を除外する方法](https://qiita.com/suin/items/e53eee56da23d476addc)
  - [Docker volumeの削除](https://qiita.com/Ikumi/items/b319a12d7e2c9f7b904d)

除外するというよりは他 volume に逃がす（永続化した）というような印象でした。結局のところ Gopkg.toml を編集する際には volume を事前に削除しないと変更前の volume でマウントされ上書きされてしまいます。

```docker-compose.yml
version: '3'

# マウント時に vendor 以下を削除してしまうため、別 volume を指定する
# Gopkg.toml を編集する場合、vendor ボリュームも削除しイメージを再構築する
volumes:
  vendor:

services:
  api:
    build:
      context: .
      dockerfile: docker/api/Dockerfile
    volumes:
      - ./src/api:/go/src/api
      - vendor:/go/src/api/vendor
    ports:
      - 3001:3001
    tty:
      true
```

## Gopkg.toml

- 参考
  - https://golang.github.io/dep/docs/new-project.html
 
Gopkg.toml は仮イメージ、仮コンテナを作成して `dep init` して作成しました。
仮イメージ、仮コンテナは削除しました。 

```Gopkg.toml
[[constraint]]
  name = "github.com/gin-gonic/gin"
  version = "1.2.0"

[prune]
  go-tests = true
  unused-packages = true
```

## main.go

[クイックスタート](https://github.com/gin-gonic/gin#quick-start)をコピペしてポート指定のみ編集しています。

```main.go
package main

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

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "ping",
		})
	})
	// ポートを設定しています。
	r.Run(":3001")
}
```

## 出力結果

これで、以下のようにブラウザからアクセスできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/61513/941ae9da-48e5-6027-33e2-f26a9b4ba66a.png)