docker-composeでGo + MySQLを起動する場合、MySQLの起動を待ってGoのWebサーバーを起動する必要があります。実現するにはどうやらスクリプトを書かないとだめらしいですが、dockerizeを使うと簡単に実現できます。
サンプル用Goサーバを作成する
起動時にusersテーブルを作成し、リクエスト時にusersテーブルにレコードをinsertする簡単なサンプルアプリケーションです。
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
)
type User struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
var db *sql.DB
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
db = Conn()
defer db.Close()
_, err = db.Exec("CREATE TABLE IF NOT EXISTS users(id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, firstname VARCHAR(255) NOT NULL, lastname VARCHAR(255) NOT NULL)")
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/users", users)
err = http.ListenAndServe(os.Getenv("LISTEN_PORT"), nil)
if err != nil {
log.Fatal(err)
}
}
func Conn() *sql.DB {
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(mysql:3306)/%s", os.Getenv("MYSQL_USER"), os.Getenv("MYSQL_PASSWORD"), os.Getenv("MYSQL_SCHEMA")))
if err != nil {
log.Fatal(err)
}
return db
}
func users(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
user := User{
FirstName: "John",
LastName: "Doe",
}
var users []User
users = append(users, user)
stmt, err := db.Prepare("INSERT INTO users(firstname, lastname) VALUES(?, ?)")
if err != nil {
log.Print(err)
return
}
_, err = stmt.Exec(user.FirstName, user.LastName)
if err != nil {
log.Print(err)
return
}
json.NewEncoder(w).Encode(users)
}
Dockerfile
FROM golang:1.14
# コンテナログイン時のディレクトリ指定
WORKDIR /opt/sandbox-go
ENV DOCKERIZE_VERSION v0.6.1
RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz
# ホストのファイルをコンテナの作業ディレクトリにコピー
COPY . .
# ビルド
RUN go build -o app main.go
# 起動
CMD ["/opt/sandbox-go/app"]
docker-compose.ymlファイル
entrypoint
にdockerize
を使ってtcp://mysql:3306
に接続できるまで待ちます。
version: '3'
volumes:
db-volume: # 追記
services:
mysql:
image: mysql:5.7.30
container_name: sandbox-docker-compose-mysql-container
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_DATABASE: sandbox-docker-compose-mysql
ports:
- 13306:3306
volumes:
- db-volume:/var/lib/mysql
app:
# コンテナ名
container_name: sandbox-docker-compose-app-container
# イメージ名
image: sandbox-docker-compose-app-image
# ビルドに使用するDockerfileがあるディレクトリ指定
build: .
# マウントディレクトリ指定
volumes:
- .:/go/src/github.com/taisa831/sandbox-docker-compose-go
ports:
- "8000:8000"
entrypoint:
# mysqlが立ち上がるまで待つ
- dockerize
- -wait
- tcp://mysql:3306
command: ["/opt/sandbox-docker-compose-go/app"]
restart: always
depends_on:
- mysql
構成
環境変数は.env
から呼び出しています。
.
├── Dockerfile
├── .env
├── docker-compose.yml
├── go.mod
├── go.sum
└── main.go
コンテナ作成&起動
$ docker-compose build
$ docker-compose up
# or
$ docker-compose up -d
Webサーバにアクセス
http://localhost:8000/users
にアクセスしてJSONが表示されます。
[{"firstName":"John","lastName":"Doe"}]
MySQLに接続
MySQLに接続してテーブルが作成されレコードがinsertされていることを確認します。
$ mysql -u user -h 127.0.0.1 -p -P 13306 sandbox-docker-compose-mysql
mysql> show tables;
+----------------------------------------+
| Tables_in_sandbox-docker-compose-mysql |
+----------------------------------------+
| users |
+----------------------------------------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+-----------+----------+
| id | firstname | lastname |
+----+-----------+----------+
| 1 | John | Doe |
| 2 | John | Doe |
| 3 | John | Doe |
+----+-----------+----------+
3 rows in set (0.00 sec)
無事にテーブルが作成されレコードがinsertされているのが確認できました。