docker-composeでgolangのフレームワークrevelとMysqlを利用した開発環境を構築する

#環境
OS : OS X El Capitan
Docker : 17.03.0-ce
docker-compose : 2
golang : 1.8
revel : 0.13.1
Mysql : 5.7.17

#動機
golangでwebアプリケーションを開発しようと思ったときに，docker-composeの練習もやりたいと思ったのでやってみた．

https://github.com/youtangai/RevelOnDocker
ここにあるのでforkすれば使えます．

#フォルダ構成
```
revel_on_docker/
	├Dockerfile
	├docker-compose.yml
	└myapp/
```
なので

```
cd 
mkdir revel_on_docker
cd revel_on_docker
```
でフォルダを作成しカレントディレクトリの変更

#Dockerfile
```
#golang v1.8が準備されているimageを利用
FROM golang:1.8.0 

#$GOPATHに/go/srcを追加．この後srcの下にアプリケーションフォルダを作成する為
ENV GOPATH $GOPATH:/go/src 

#とりあえず更新
RUN apt-get update && \
    apt-get upgrade -y
    
#revel，revel-cli，gorm，go-sql-driverのインストール
#revelにはORMがないので
RUN go get github.com/revel/revel && \
    go get github.com/revel/cmd/revel && \
    go get github.com/jinzhu/gorm && \
    go get github.com/go-sql-driver/mysql

#アプリケーション(myapp)をマウントするためのディレクトリを作成
RUN mkdir /go/src/myapp

#revelはポート9000で実行されるのでポート9000の開放
EXPOSE 9000
```

#docker-compose.yml
```
version: '2' #docker-composeのバージョンを指定
services:
    db:
        image: mysql:5.7 #mysql5.7が準備されているimageを指定
        environment:
            - MYSQL_ROOT_PASSWORD=secret #rootのパスワード
            - MYSQL_DATABASE=revel #revelデータベースの作成
            - MYSQL_USER=revel #revelユーザの作成
            - MYSQL_PASSWORD=secret #revelユーザのパスワード
    web:
        build: . #Dockerfileをビルド
        command: revel run myapp #docker-compose up の際にアプリケーション実行
        volumes:
            - ./myapp:/go/src/myapp #作成したフォルダにアプリケーションをマウント
        ports:
            - 9000:9000 #ポート9000番の開放
        depends_on:
            - db #dbとつなげる
```

#myappの作成
```
revel new myapp
```
を実行すると自分の環境の$GOPATH/src以下に myappフォルダが作成されるので．

```
cp -r /path/to/go/src/myapp .
```
を実行しrevel_on_dockerにmyappをコピー

#Mysql接続設定
DBの接続情報をmyapp/conf/app.confの[dev]セクションに記述する

```myapp/conf/app.conf
[dev]

・・・省略・・・
#connection string for mysql
db.user = revel
db.password = secret
db.host = db
db.port = 3306
db.name = revel
db.protocol = tcp

```

次にmyapp/appの下にmodelsフォルダを作成．
modelsの下に接続するための処理を記述

```myapp/app/models/gorm.go
package models

import (
  "github.com/revel/revel"
  "github.com/jinzhu/gorm"
  "strings"
  "time"
  "fmt"
  _"github.com/go-sql-driver/mysql"
)

var DB **gorm.DB

func InitDB() {
  db, err := gorm.Open("mysql", getConnectionString())

  if err != nil {
    revel.ERROR.Println("FATAL", err)
    panic(err)
  }

  db.DB()
  DB = &db
}

type Model struct {
  gorm.Model
  ID        uint `gorm:"primary_key"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt *time.Time
}

type Validator interface {
  IsSatisfied(interface{}) bool
  DefaultMessage() string
}

func getParamString(param string, defaultValue string) string {
    p, found := revel.Config.String(param)
    if !found {
        if defaultValue == "" {
            revel.ERROR.Fatal("Cound not find parameter: " + param)
        } else {
            return defaultValue
        }
    }
    return p
}

func getConnectionString() string {
    host := getParamString("db.host", "")
    port := getParamString("db.port", "3306")
    user := getParamString("db.user", "")
    pass := getParamString("db.password", "")
    dbname := getParamString("db.name", "")
    protocol := getParamString("db.protocol", "tcp")
    dbargs := getParamString("dbargs", " ")
    timezone := getParamString("db.timezone", "parseTime=true&loc=Asia%2FTokyo")

    if strings.Trim(dbargs, " ") != "" {
        dbargs = "?" + dbargs
    } else {
        dbargs = ""
    }
    return fmt.Sprintf("%s:%s@%s([%s]:%s)/%s%s?%s", user, pass, protocol, host, port, dbname, dbargs, timezone)
}
```
InitDBが初期化処理なので，InitDBがアプリケーション実行時に実行されるようにする

```myapp/app/init.go
func init() {
	/*省略*/
	revel.OnAppStart(models.InitDB) // init database
}
```

#試す
revel_on_docker内で

```
docker-compose up
```
を実行し，ブラウザで localhost:9000にアクセスして
It worksと表示されれば成功です．

#参考
http://qiita.com/sawadashota/items/8059ecf0415985b12a56
http://qiita.com/puttyo_bubu/items/cc320148ce69792619d3