🐋

【Go, Docker】docker composeでGoとMySQLをLocalで動かす

2022/02/13に公開

はじめに

  • DockerfileでGoのimageを作成し、そのDockerfileと、MySQLのimageを使い、GoのコードでDBを使ってみます。
  • ORMはXormを使います。

環境

  • go 1.17
  • macOS 12.0.1
  • M1チップ
  • github.com/go-sql-driver/mysql v1.6.0
  • xorm.io/xorm v1.2.5

ゴール

  • docker-compose up -dで起動
  • docker-compose exec app go run main.goでmain.goを呼ぶ。
  • Xormにデータが追加され、取得出来たものが取得されたら成功です。

ソースコード

Dockerfile

FROM golang:1.17.0-alpine3.14

ENV ROOT=/go/src/app
WORKDIR ${ROOT}

RUN apk update && apk add git

COPY ./main.go ${ROOT}

COPY go.mod ${ROOT}

RUN go mod tidy

docker-compose.yml

version: "3"
services:
  app:
    build: .
    depends_on:
    - db
    volumes:
      - ./:/go/src/app
    tty: true

  db:
    image: mysql:5.7
    environment:
    - MYSQL_DATABASE=test_db
    - MYSQL_ROOT_PASSWORD=password
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --innodb_file_per_table
      --innodb_file_format=BARRACUDA
      --innodb_large_prefix=1
    ports:
      - 3306:3306

main.go

package main

import (
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
	"xorm.io/xorm"
)

type User struct {
	ID   int64  `xorm:"id pk autoincr"`
	Name string `xorm:"name"`
	Age  int    `xorm:"age"`
}

// createTable テーブルを作成する
func createTable(engine xorm.Engine) {
	err := engine.CreateTables(User{})
	if err != nil {
		log.Fatalf("テーブルの生成に失敗しました。: %v", err)
	}
	fmt.Println("テーブル作成が成功しました。")
}

// insert テーブルにレコードを追加する
func insert(engine xorm.Engine) {
	user := User{
		Name: "tanaka",
		Age:  20,
	}
	_, err := engine.Table("user").Insert(user)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("レコードの追加が完了しました。")
}

// get 単体取得(1レコードを取得)
func get(engine xorm.Engine) {
	user := User{}
	// idフィールドは Autoincrement なので Insert済みなのであれば id = 1 のユーザが取得できるはず
	result, err := engine.ID(1).Get(&user)
	if err != nil {
		log.Fatal(err)
	}
	if !result {
		log.Fatal("ユーザーが見つかりませんでした。")
	}
	fmt.Printf("取得したレコード :%+v\n", user)
}

func main() {
	//engineを作成します。
	engine, err := xorm.NewEngine("mysql", "root:password@tcp(db:3306)/test_db?charset=utf8mb4&parseTime=true")
	if err != nil {
		log.Fatal(err)
	}

	//テーブルを作成する
	createTable(*engine)
	//テーブルに追加する
	insert(*engine)
	//テーブルから取得する
	get(*engine)

	fmt.Println("うまく動きました。")
}

解説

Dockerfile

下記にコメントで書いた通りです。
go mod installではなく、go mod tidyを使ってます。
go mod tidy使うと必要なものはinstallしてくれて、要らないものは削除してくれます。
ENVは使わなくても良いんですが、何回もPATH指定するの面倒くさいので、環境変数にしました。

//goのベースイメージで1.17を使います。
FROM golang:1.17.0-alpine3.14

// ROOTという名前で、`/go/src/app`を定義します。
ENV ROOT=/go/src/app
// WORKDIRを/go/src/appにします。
WORKDIR ${ROOT}

// gitをインストールします。
RUN apk update && apk add git

// main.goを/go/src/appにコピーします。
COPY ./main.go ${ROOT}
// go.modを/go/src/appにコピーします。
COPY go.mod ${ROOT}

//go mod tidyを実行します。
RUN go mod tidy

docker-compose.yml

  • version
    • docker-composeのversionです。
  • services
    • docker-compose.ymlで扱うコンテナです。
    • 今回はappdbという名前のコンテナを使います。
    • appdbという名前は適当です。
  • app
    • build: .
      • カレントディレクトリのDockerfileをビルドします。
      • 上で作成した、Goのイメージを使っているDockerfileがビルドされます。
    • depends_on:
      • これは○○の後で実行するというものです。
      • 今回はdbのコンテナの実行後にappのコンテナを起動させます。
    • volumes:
      • データを永続化する場所を指定します。
      • 今回は/go/src/appを指定します。
    • tty: true
      • trueにしておく事でコンテナを継続させる事ができます。
  • db
    • image: mysql:5.7
      • これはMySQLオフィシャルのDockerイメージです。
      • このようにDockerfileに書かなくても、docker-composeにこのように書くだけでオフィシャルのMySQL使えます。
      • 今回はMySQL5.7を使用します。
    • environment:
      • 環境変数です。
      • MYSQL_DATABASE=test_db
        • データベース名です。test_dbという名前にしてます。
      • MYSQL_ROOT_PASSWORD=password
        • ROOTパスワードです。passwordというパスワードにしてます。
    • command: >
      • オプションです。
      • 下記2つは正直よく分かってませんが、文字キャラクターをutf8mb4にする為のものです。
        --character-set-server=utf8mb4
        --collation-server=utf8mb4_general_ci
    • ports:
      • ポートを指定します。
      • MySQLなので3306を利用します。
version: "3"
services:
  app:
    build: .
    depends_on:
    - db
    volumes:
      - ./:/go/src/app
    tty: true

  db:
    image: mysql:5.7
    environment:
    - MYSQL_DATABASE=test_db
    - MYSQL_ROOT_PASSWORD=password
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
    ports:
      - 3306:3306

main.go

	//engineを作成します。
	engine, err := xorm.NewEngine("mysql", "root:password@tcp(db:3306)/test_db?charset=utf8mb4&parseTime=true")
	if err != nil {
		log.Fatal(err)
	}

ここでengineの作成をしてます。
db:3306dbの部分はコンテナの名前です。
/test_db?test_dbはデータベースの名前です。

さいごに

上記のコードで、コマンドを実行すれば動くはずです。
これであなたも、DockerでGoとMySQLが使えるハズ!!

参考

Discussion