ローカル環境で開発するときに、MySQL を Docker で動かしてみる

# はじめに

手元の開発環境でプログラムを開発するときに、MySQL に接続したくなる時が有ります。クラウド上でのマネージドサービスを使ってもよいのですが、費用など掛かるためローカルで MySQL を動かしたくなります。そこで、Docker を使って MySQL を動作させる方法がかなりお手軽だと思います。

この記事では、ローカルで MySQL を動かしたうえで、Go言語から接続する手順を残しておきます。



# Docker で MySQL を動かす

ECR Public で公開されている Docker Image を使って、ローカル上で MySQL を動かします。Docker Hub でもよいのですが、スロットリングの上限が自分の場合は 6時間につき 100 が上限となっているため、ECR Public を使っていきます。

docker run のコマンド一発でローカル環境で MySQL が動作できます。コンテナサイコー。

- MySQL 8.0 を利用
- MySQL のパスワードなどを指定

```
docker run \
--name mydb \
-itd \
--hostname my-mysql \
-e MYSQL_ROOT_PASSWORD=mypassword \
-e BIND-ADDRESS=0.0.0.0 \
-p 3306:3306 \
public.ecr.aws/docker/library/mysql:8.0
```



なお、ここで動作した MySQL コンテナを削除する場合は次のコマンドで削除可能です。

```
docker kill mydb
docker rm mydb
```



MySQL が正常に稼働しているか、接続テストを行います。

```
mysql -u root -h 127.0.0.1 --port=3306 -pmypassword
```



実行例です。問題なく接続できました。

```
> mysql -u root -h 127.0.0.1 --port=3306 -pmypassword
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.28 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 
```



`SHOW DATABASES` でデータベース一覧も確認してみましょう。正常に見えていますね。

```
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

mysql> 
```



# テスト用のデータを格納

テスト用のデータ格納します。

```
CREATE DATABASE sugi01;
USE sugi01;

CREATE TABLE sample(
  id INT(11) NOT NULL AUTO_INCREMENT,
  name VARCHAR(10) NOT NULL,
  PRIMARY KEY (id)
);

INSERT INTO sample(name) VALUES ("MySQLのデータ");
```



確認

```
SELECT * FROM sugi01.sample;
```



実行例

```
mysql> SELECT * FROM sugi01.sample;
+----+-------------------+
| id | name              |
+----+-------------------+
|  1 | MySQLのデータ     |
+----+-------------------+
1 row in set (0.00 sec)

mysql> 
```



# 環境変数の設定

Go言語をつかって動作確認をしていくのですが、接続先の情報は環境変数として渡したいと思います。環境変数化しておくと、なにかと便利です。



## Bash

Bash の場合の設定例

```
export MYSQL_HOSTNAME=localhost
export MYSQL_PORT=3306
export MYSQL_USERNAME=root
export MYSQL_PASSWORD=mypassword
```



## Fish

Fish の場合の設定例

```
set -x MYSQL_HOSTNAME localhost
set -x MYSQL_PORT 3306
set -x MYSQL_USERNAME root
set -x MYSQL_PASSWORD mypassword
```



# Go から接続

Go 言語用プロジェクト用のディレクトリを作成します。

```
mkdir ~/godir/app-runner-testapp
cd ~/godir/app-runner-testapp
```



MySQL 接続用のライブラリを取得します。

```
go get -u github.com/go-sql-driver/mysql
```



Goの動作確認用プログラム。このコードは、エラーのハンドリングはまったくしていないので、本番環境での利用はだめです。

- MySQL の接続先に環境変数を利用
- 1行分のみのデータを取得して、標準出力にプリント

```go
package main

import (
	"database/sql"
	"os"
	"time"

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

func main() {
	mysql_hostname := os.Getenv("MYSQL_HOSTNAME")
	mysql_port := os.Getenv("MYSQL_PORT")
	mysql_username := os.Getenv("MYSQL_USERNAME")
	mysql_password := os.Getenv("MYSQL_PASSWORD")

	db, err := sql.Open("mysql", mysql_username+":"+mysql_password+"@tcp("+mysql_hostname+":"+mysql_port+")/sugi01")
	if err != nil {
		println("MySQL のコネクション接続に失敗")
		panic(err)
	}
	defer db.Close()

	// See "Important settings" section.
	db.SetConnMaxLifetime(time.Minute * 3)
	db.SetMaxOpenConns(10)
	db.SetMaxIdleConns(10)

	row := db.QueryRow(`select * from sample`)

	var id, name string
	row.Scan(&id, &name)

	println(name)
}
```



Go の依存関係を管理するための `go.mod` を生成

```
go mod init github.com/Sugi275/app-runner-testapp
```



# 動作確認

それでは動作確認をしてみましょう。「MySQLのデータ」と表示されており、正常に表示されることがわかります。

```
> go run app.go
MySQLのデータ
```