Go + gorm + gin と mysqlの環境をDockerで作ったった

Go + gorm + gin と mysqlと言うありきたりな組み合わせでDockerの環境作りましたー！

今更ですがDocker触り始めて軽さに感動😭

環境もがっつり作ったのは初めてかも。。

以下の記事参考させていただきました！
[Dockerで立てたmysqlにgolangから接続する方法](https://qiita.com/kotamat/items/57e853b6298bff5b3d81)
[[golang]gormを使ってローカル環境のMySQLとCRUD操作](https://qiita.com/gatapon/items/e788c571c2cc7e8abb60)
[他のDockerコンテナからコンテナ内のMySQLに接続する](https://qiita.com/YuitoSato/items/4a4b46f5670b45739a37)

### ディレクトリ構成
こんな感じ

```
/
├ docker-compose
├ .dockerignore
├ docker/
│　└ api/
│　　　└ Dockerfile
│　└ db/
│　　　└ Dockerfile
│　　　└ conf.d
│　　　  └ mysql.conf 
├ src
   └ api/
      └ main.go
      └ start_app.sh
```

### Dockerfile
#### docker/api/Dockerfile
どこでも見るような感じになってますが `CMD` が結構ネックです！

```dockerfile

FROM golang:latest

COPY src/api /go/src/api  ← GOROOTが/goになるので

WORKDIR /go/src/api/

RUN go get -u github.com/gin-gonic/gin \　　← gormとginとドライバー
  && go get github.com/jinzhu/gorm \
  && go get github.com/go-sql-driver/mysql
  && apt-get install -y mariadb-client

CMD ["sh", "./start_app.sh"]  ←ハマった。。
```

#### docker/db/Dockerfile
こちらもそこまで特筆することはありません！

```dockerfile

FROM mysql:5.7

RUN touch /var/log/mysql/mysqld.log ← ログファイル作っときましょう
```

### docker-compose
上で作った２つのコンテナを取り扱う為にdocker-composeを使います。

```dockerfile

version: '3'
services:
  api:
    links:
      - mysql　← サービス名(下のmysql)は好きな物で大丈夫です。
    build: ← buildの中にこの２つ書くと一番上のディレクトリから色々弄れる感覚です。
      context: . 
      dockerfile: ./docker/api/Dockerfile
    ports:
      - "8080:8080"
    volumes:
      - ./src/api:/go/src/api
  mysql:
    build: ./docker/db
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: sample
    hostname: mysql
    ports: 
      - "3306:3306"
    volumes:
      - ./docker/db/conf.d:/etc/mysql/conf.d
      - ./log/mysql:/var/log/mysql
```

### conf.d/mysql.conf
これはmysqlの設定ファイルなんで参考までに！
（丸パクリさせてもらいましたw）

```conf

[mysqld]
character-set-server=utf8mb4       # mysqlサーバー側が使用する文字コード
explicit-defaults-for-timestamp=1　  # テーブルにTimeStamp型のカラムをもつ場合、推奨
general-log=1　                  # 実行したクエリの全ての履歴が記録される（defaultではOFFになっているらしい）
general-log-file=/var/log/mysql/mysqld.log # ログの出力先

[client]
default-character-set=utf8mb4　　　　　　　　　　　　　　　# mysqlのクライアント側が使用する文字コード
```

### src/start_app.sh
ここすごいハマりました。。
結論から言うとmysqlサーバーが立ち上がる前にapiサーバーが立ち上がってしまうので立ち上がりを待つようにしています。(確実にもっと良い書き方あります。。)

```shell

# !/bin/bash

# MySQLサーバーが起動するまで待機する
until mysqladmin ping -h mysql -P 3306 --silent; do
  echo 'waiting for mysqld to be connectable...'
  sleep 2
done

echo "app is starting...!"
exec go run main.go
```

### src/main.go
gormとginを使うとこまでなので多くは書いてません！
なんで他のパッケージに公開してるかは突っ込まないでくださいw

```go

package main

import (
	"github.com/gin-gonic/gin"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
	DBMigrate(DBConnect())
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "成功",
		})
	})
	r.Run(":8080")
}

type User struct {
	gorm.Model
	NickName string `json:"nickName"`
}

func DBMigrate(db *gorm.DB) *gorm.DB {
	db.AutoMigrate(&User{})
	return db
}


func DBConnect() *gorm.DB {
	DBMS := "mysql"
	USER := "root"
	PASS := "password"
	PROTOCOL := "tcp(mysql:3306)"  ← ここのmysqlはサービス名です
	DBNAME := "sample"
	CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?parseTime=true"
	db, err := gorm.Open(DBMS, CONNECT)
	if err != nil {
		panic(err.Error())
	}
	return db
}

```

### 起動

```sh

docker-compose build
docker-compose up
```

起動が確認できたら

```sh

curl http://localhost:8080/ping
```

で成功が返ってこれば問題ないです！

```sh

docker-compose up -d
```

を使っても良いんですけどどこかミスってて落ちてるの気づけないので最初はupで行きましょう！

### 終わり

mysqlサーバーとAPIサーバーの立ち上がりの順番でめちゃハマりました。。。