やりたいこと
普通にイメージを作成するとどうしても大きくなってしまうGoイメージですが、multi-stage buildsにすると
格段にサイズが小さくすることができます。
今回はdocker(docker-compose)で環境を準備し Go から MySQL にアクセスする方法について書いていきます。
基本的に、以前自分が勉強でtodolist用のAPIを作成するために作成したリポジトリからの出典になります。
https://github.com/t0w4/toDoListBackend
Dockerfile
FROM golang:1.11.2-alpine3.8 AS build
WORKDIR /
COPY . /go/src/github.com/t0w4/toDoListBackend
RUN apk update \
&& apk add --no-cache git \
&& go get github.com/go-sql-driver/mysql \
&& go get github.com/google/uuid \
&& go get github.com/gorilla/mux
RUN cd /go/src/github.com/t0w4/toDoListBackend && go build -o bin/todolist main.go
FROM alpine:3.8
COPY --from=build /go/src/github.com/t0w4/toDoListBackend/bin/todolist /usr/local/bin/
CMD ["todolist"]
goのdockerの公式サイトも見ましょう。
docker上では$GOPATHが /go になることも注意しましょう。
docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
volumes:
- mysql_data:/var/lib/mysql
- ./sqls/init:/docker-entrypoint-initdb.d
ports:
- "3306:3306"
restart: always
environment:
MYSQL_ROOT_PASSWORD: gerhuhaer
MYSQL_DATABASE: todoList
MYSQL_USER: t0w4
MYSQL_PASSWORD: faweufhli
todolist:
build: .
depends_on:
- db
ports:
- "8080:8080"
environment:
MYSQL_DB_HOST: db
MYSQL_DB: todoList
MYSQL_PORT: 3306
MYSQL_USER: t0w4
MYSQL_PASSWORD: faweufhli
restart: always
volumes:
mysql_data:
注意!!!!!!!
今回特に外部公開もしていないのに勉強用だからいいですが、外部から見えるような場所でID, パスワードをほいほい公開しないようにしましょう。
各環境変数の要不要、意味については公式を読みましょう。下手解説より100倍いいです。
/docker-entrypoint-initdb.d
にsqlを配置すると初期起動時に実行してくれるますので、DBやテーブルの作成、初期データの投入などの用途で使えます。
また永続化のためMySQLのデータはローカルにマウントさせています。
GoでのMySQLへのアクセス
GoでMySQLを扱う部分についてはRevelでGORMを使ったMySQL Associationの実装が参考になったので
そちらを見てください。。。。だと不親切なので、以下に自分がORMを使わないで書いた実装があるんで載せます。
package db
import (
"database/sql"
"fmt"
"os"
"strings"
_ "github.com/go-sql-driver/mysql"
)
func Init() (*sql.DB, error) {
connectionString := getConnectionString()
db, err := sql.Open("mysql", connectionString)
if err != nil {
return nil, err
}
return db, nil
}
func getParamString(param string, defaultValue string) string {
env := os.Getenv(param)
if env != "" {
return env
}
return defaultValue
}
func getConnectionString() string {
host := getParamString("MYSQL_DB_HOST", "localhost")
port := getParamString("MYSQL_PORT", "3306")
user := getParamString("MYSQL_USER", "root")
pass := getParamString("MYSQL_PASSWORD", "")
dbname := getParamString("MYSQL_DB", "todoList")
protocol := getParamString("MYSQL_PROTOCOL", "tcp")
dbargs := getParamString("MYSQL_DBARGS", " ")
if strings.Trim(dbargs, " ") != "" {
dbargs = "?" + dbargs
} else {
dbargs = ""
}
return fmt.Sprintf("%s:%s@%s([%s]:%s)/%s%s",
user, pass, protocol, host, port, dbname, dbargs)
}
差分は、initの部分と、参考記事が設定ファイルから取得していたところを環境変数から取得するようにしたところくらいです。
自分が開発していた時は、このgetConnectionString
が返すMySQLの接続情報がわからず時間を食ってしまいました。。。
終わりに
記事としてはとても短いので「えっ!これだけ?」と思われるかもしれないですが、意外と上記の内容がまとまった記事というのが見つからなかったので、今後Goをdockerで作っていきたい人たちの参考になれば嬉しいです。