文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

macにdocker-machineで使い捨てのmysqlサーバをたてる

dockerならローカルに複数バージョンの使い捨てのMySQLサーバをたてられるので便利なのです。
f:id:treeapps:20151128225319p:plain
標準スキルになっていきそうな勢いのdocker。今回はmacのローカル環境にdockerを使ってmysqlサーバをたててみようと思います。

今までmysqlのサイトからインストーラーをDLしてMySQLサーバをインストールしていましたが、複数バージョンインストールしたい場合等に困っていました。dockerならver5.6のコンテナ、ver5.7のコンテナ、と簡単に作成・破棄できてしまいます。ローカル環境に色々インストールしたりして環境を汚す量も減らす事ができます。

では簡単に手順を書いてみます。

この記事でやること

目的

以下を何とかしたいのです。

  • ローカルのmacに複数のMySQLサーバを「簡単に職人芸不要で」たてたい。
  • ローカルの環境をなるべく汚したくない。

プロジェクトによってMySQLのバージョンが異なる場合が多かったり、最新バージョンをいち早く試してみたい時に、いちいちローカルにMySQLサーバをたてるのはいやですね。ローカルの環境も汚れるし、複数バージョンを動かすのに職人芸的な設定をするのも嫌です。多分途中で職人芸を忘れて維持できなくなるかもしれないです。また、ローカルのマシンを新調したりしたらまたインストール・環境設定のやり直しかと思うと気が滅入ります。

手段

  • docker-machineでdockerホストを作成する。
  • mysql5.7のコンテナを作成する。
  • macのローカルからコンテナ上のmysql5.7に対してリモートで操作する。

今回はdockerホスト作成にdocker-machineを使います。VagrantにCoreOSをインストールしてdockerしてもいいですが、やはりdocker-machineが楽だと思います。

ローカルにdocker環境を構築する

virtualboxまたはVMWareFusionをインストール

仮想環境をローカルに構築する際に、virtualboxやVMWareFusionが必要になります。

まずは無料のvirtualboxで試すのがいいと思います。もう既にVMWareFusionを購入していれば、それをそのまま使用できます。

Oracle VM VirtualBox

VMWarePlayerではだめです。仮想環境を作成できるVMWareでなければなりません。VMWareFusion・VMWareFusion pro等なら大丈夫です。

docker-toolboxのインストール

docker関連のソフトウェア一式が入っているのがdocker-toolboxです。特に理由が無ければこれをインストールするのが一番楽です。
https://www.docker.com/docker-toolboxwww.docker.com

docker-machineでdockerホストを作成する

docker-machineは、dockerホストOSの環境を構築するためのソフトウェアです。docker-toolboxをインストールするとdocker-machineもインストールされます。

docker-machineでホストを作成し、ホストOSにdockerコンテナを作成していきます。

docker-machineには以下のように最初から「default」という名前で仮想環境が作成されていますが、新たに使い捨て用にホストOSを作成します。環境の名前を「dev」として進めています。

tree:~ tree$ docker-machine ls
NAME      ACTIVE   DRIVER         STATE     URL                        SWARM
default   -        virtualbox     Stopped
virtualboxの場合
docker-machine create --driver virtualbox dev
VMWareFusionの場合
docker-machine create --driver vmwarefusion dev

このコマンドは、virtualboxまたはvmwarefusionに対して仮想環境を構築するコマンドです。私の環境はVMWareFusion pro v8なので、実際vmwareを開いてみると、以下のように作成されていました。
f:id:treeapps:20151128205100p:plain

docker-machineに作成したホストOSの存在・状態を確認する
tree:~ tree$ docker-machine ls
NAME      ACTIVE   DRIVER         STATE     URL                        SWARM
default   -        virtualbox     Stopped
dev       -        vmwarefusion   Running   tcp://172.16.53.131:2376

devができていますね。dockerホスト作成と同時にOSの起動処理も行われており、STATEがRunningになっている事が解ります。

豆知識:dockerホストのOSは何が使われているの?
tree:~ tree$ docker-machine ssh dev cat /etc/issue
Core Linux

Core Linux(TinyCoreLinux?)だそうです。

ローカルの環境変数を設定

docker-machine create した際に表示されるログに、以下の一文があります。

To see how to connect Docker to this machine, run: docker-machine env dev

「dockerホスト上のコンテナに接続するための方法は、このマシンで docker-machine env dev を実行して確認してね」と言っています。

では「docker-machine env dev」を実行してみましょう。

tree:~ tree$ docker-machine env dev
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://172.16.53.131:2376"
export DOCKER_CERT_PATH="/Users/tree/.docker/machine/machines/dev"
export DOCKER_MACHINE_NAME="dev"
# Run this command to configure your shell:
# eval "$(docker-machine env dev)"

どうやら環境変数を標準出力しただけのようですね。まだ環境変数は設定できていません。こちらもコマンド実行時のログの最後に「Run this command to configure your shell:」と書いてあるので、今度は「eval "$(docker-machine env dev)"」を実行してみます。

tree:~ tree$ eval "$(docker-machine env dev)"
tree:~ tree$

特にログは出ません。ではローカルの環境変数がどうなったのかを確認してみます。

tree:~ tree$ env | grep -i docker
DOCKER_HOST=tcp://172.16.53.131:2376
DOCKER_MACHINE_NAME=dev
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/Users/tree/.docker/machine/machines/dev

おお、先ほどの「docker-machine env dev」の結果が反映されましたね。しかしこの環境変数は一時的な設定なので、ターミナルソフトを再起動しただけで消えてしまいます。今回はお試しなので、その辺りはまた今度にしましょう。

この環境変数が設定されると、ローカルのターミナルでdockerコマンドを実行すると、そのコマンドはmacのローカルのdockerではなくdocker-machineで作成したdockerホストに向けて実行され、更にdockerホスト上のコンテナに伝搬されます。つまりdockerホストを意識せず、直接ローカル環境からコンテナに対してコマンドが実行できるようになります。従って、dockerホストにsshしてdockerコマンドを実行、等といった事をしなくてよくなります。これは大変便利ですね。

なお、docker-machine createで作成されるホストOSのIPはコロコロ変わるため、ホストOSを新たに作成した場合は都度「$(docker-machine env dev)」します。

dockerのイメージをダウンロードする

先ほど作成したdockerホスト上に、dockerコンテナと呼ぶOSをインストールするために、dockerのイメージをダウンロードする必要があります。

今回使用するのは、MySQL公式のdockerイメージです。

今回はMySQL5.7を使います。docker-machineのdevが起動している状態で、ローカルのmacで以下のコマンドを実行します。

docker pull mysql:5.7

pull(ダウンロード)すると、以下のようにダウンロードが始まります。そこそこのファイルサイズなので、回線が細いとかなり時間がかかります。

tree:~ tree$ docker pull mysql:5.7
5.7: Pulling from library/mysql

1565e86129b8: Downloading [=================================>                 ] 34.08 MB/51.35 MB
a604b236bcde: Download complete
2a1fefc8d587: Download complete
f9519f46a2bf: Download complete
35e21079caee: Download complete
b08f3d26d732: Download complete
ced60f6188d8: Download complete
93148df18c31: Download complete
8587beca5034: Download complete
2593a05c664f: Downloading [=============================================>     ] 57.85 MB/63.42 MB
1483cfdf29e5: Download complete
1366ffba5c3b: Download complete
4e07f9c5fa5e: Download complete
1c19ce71381b: Download complete
d6a18d40a940: Download complete
0f1a7d5b17f5: Download complete

MySQLのdockerコンテナを作成する

コンテナにマウントするファイルの用意

コンテナ作成前に、コンテナに対してこちらで用意したmy.cnfを反映したいので、ローカルにmy.cnfを作成します。試しに「/usr/local/docker/mysql/conf.d/my.cnf」と作成してもコンテナにマウントできなかった(恐らくSIPの問題?)なので、ホーム直下等に用意します。

# マウントするためのフォルダを作成
mkdir -pv $HOME/docker/mysql/conf.d

# my.cnfの作成
cat << EOF > $HOME/docker/mysql/conf.d/my.cnf
[client]
port=3306
default-character-set = utf8mb4

[mysqld]
port=3306
character-set-server = utf8mb4
skip-character-set-client-handshake
skip-name-resolve
lower_case_table_names = 1
default-storage-engine = InnoDB
innodb_file_format = Barracuda
innodb_file_per_table = 1
EOF

my.cnfの内容は任意に変更して下さい。とりあえず文字コードは変更しておきたいですね。

豆知識:MySQLコンテナが用意しているデフォルトのmy.cnf

公式のMySQLコンテナのmy.cnfですが、/etc/my.cnfではなくて、/etc/mysql/my.cnf に配置されています

my.cnfはちょっと行数が多いので抜粋すると、以下が記述されている点に注目です。

# * IMPORTANT: Additional settings that can override those from this file!
#   The files must end with '.cnf', otherwise they'll be ignored.
#
!includedir /etc/mysql/conf.d/

/etc/mysql/conf.d/ 配下に置かれたファイルを動的に読み込む設定がされており、/etc/mysql/my.cnfの設定を上書きして値を読みこませる事ができるようになります。従って/etc/mysql/my.cnfを直接編集するのではなく、/etc/mysql/conf.d/my.cnfに上書きしたい値を記述する事になります。

MySQLのコンテナを作成・起動する

コンテナ作成コマンドは以下です。

docker run --name mysql5.7 -p 3307:3306 -v ~/docker/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_DATABASE=hoge -e MYSQL_USER=worker -e MYSQL_PASSWORD=worker -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

はい。一気に意味不明になりましたね。オプションが非常に多いです。

コマンドを分解してそれぞれ見ていきます。

run コンテナを起動する。
--name コンテナに名前を付ける。ここでつけた名前で今後dockerコマンドを実行します。
-p ポートフォワードします。左がホストのportで右がコンテナのportです。ホストの3307に接続するとコンテナの3306に接続されます。
-v ローカルのディレクトリをコンテナにマウントします。macの場合は/usr/local配下SIPが絡むので避けましょう。
-e コンテナに対して環境変数を設定します。複数設定する事ができます。
-d デーモン起動。通常dockerコマンド終了時にコンテナは破棄されますが、今回はデーモン起動してコンテナを常駐起動させています。
mysql:5.7 どのイメージで起動するかを指定します。「リポジトリ名:タグ名」の書式です。docker images実行時の「REPOSITORY」と「TAG」です。

ポートフォワードを3307:3306としたのは、既にローカルにDMG形式等でMySQLがインストールされている場合等を考慮したためです。3307も既に使用しているなら、任意に割り当てて下さい。

ここで設定した「-e」の環境変数ですが、これは公式のMySQLイメージが「こういう環境変数を指定すると、コンテナ起動時に指定したデータベース作成・ユーザ作成するよ」みたいなルールがあるためです。今回は「hoge」というデータベースを作成し、workerというユーザをworkerというパスワードで作成する、という設定をしています。変数の詳細は以下の公式サイトをご覧下さい。

では実際にコマンドを実行し、「docker ps」で実行中のコンテナを確認してみます。

# コンテナの起動(作成)
tree:conf.d tree$ docker run --name mysql5.7 -p 3307:3306 -v ~/docker/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_DATABASE=hoge -e MYSQL_USER=worker -e MYSQL_PASSWORD=worker -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
af659f14b7673209e99b56be39e8427c538164f06e202635e4efd1309076db2e

# 起動したコンテナの状態を確認
tree:conf.d tree$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
af659f14b767        mysql:5.7           "/entrypoint.sh mysql"   12 minutes ago      Up 12 minutes       0.0.0.0:3307->3306/tcp   mysql5.7

いますね。

ローカルからdockerコンテナのMySQLに接続してみる

dockerコンテナをrunしたので、こちらで用意したmy.cnfを読み込んで、MySQLサーバが起動されました。ではローカルのmacから作成したMySQLコンテナにリモートで接続してみます。

mysql -h$(docker-machine ip dev) -P3307 -uworker -pworker hoge

これで接続できます。しかし、コンテナ側のMySQLプロセスが完全に起動するまでは接続できないので、コンテナ起動直後に接続しようとしても以下のようになる場合があります。その場合はほんの少し時間をおいて接続しましょう。

tree:conf.d tree$ mysql -h$(docker-machine ip dev) -P3307 -uworker -pworker hoge
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on '172.16.53.131' (61)

ローカルから直接コンテナのMySQLに接続できるのは、ローカルで「-h」で指定したIP(docker-machineで作成したdockerホスト)にport=3307で接続すると、dockerホストが3307->3306というポートフォワードをし、dockerコンテナに中継して接続してくれるためです。

「-h$(docker-machine ip dev)」としているのは、dockerホストを再作成した場合等はIPが変わってしまうため、動的にIPを指定するためにそのように設定しています。

my.cnfが反映されているか確認する

my.cnfがマウントされているか
tree:conf.d tree$ docker exec -it mysql5.7 cat /etc/mysql/conf.d/my.cnf
[client]
port=3306
default-character-set = utf8mb4

[mysqld]
port=3306
character-set-server = utf8mb4
skip-character-set-client-handshake
skip-name-resolve
lower_case_table_names = 1
default-storage-engine = InnoDB
innodb_file_format = Barracuda
innodb_file_per_table = 1

また新たなコマンド「exec」が出てきましたね。

exec 起動中のdockerコンテナに対してコマンドを直接実行する。
-it -iはinteractive、対話式のコマンドを実行できるようにする。-tはtty、コマンドの入出力を可能にする。
mysql5.7 docker run --name で指定したコンテナ名です。
cat /etc/mysql/conf.d/my.cnf コンテナに対して実行したいコマンド。

今回はコンテナに直接コマンドを実行して確認してみました。もしコンテナにsshして色々確認してみたい場合は以下のコマンドでsshします。

docker exec -it mysql5.7 bash

最後のbashは、「ログインシェルを/bin/bashとしてコンテナにログインする」という意味になります。以下と同じです。

docker exec -it mysql5.7 /bin/bash

これでコンテナに直接sshする事も可能です。

MySQLの文字コードはちゃんと指定したUTF系になっているか確認
tree:conf.d tree$ mysql -h$(docker-machine ip dev) -P3307 -uworker -pworker hoge --table -e "show variables like 'char%'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

よし、文字コードが全てUTF系になりましたね。これで心置きなくテストできます!

おまけ

コンテナの破棄

docker rmコマンドでコンテナを破棄(削除)できます。

rmの引数にコンテナのidが必要なので、まずはdocker psで削除したいコンテナのidを確認します。

tree:conf.d tree$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
af659f14b767        mysql:5.7           "/entrypoint.sh mysql"   50 minutes ago      Up 50 minutes       0.0.0.0:3307->3306/tcp   mysql5.7

起動中のコンテナを強制破棄する際は「-f」を付けます。

docker rm -f af659f14b767

これで削除できます。しかしidは実は前方一致で省略する事ができます。

tree:conf.d tree$ docker rm -f af
af

こんな感じに削除できるので、きっちり入力する必要はありません。ちなみに先頭1文字でも削除できます。

virtualboxとvmwareのドライバ、どっちが速い?

私はVMWareFusion pro v8をブラックフライデーのセールで40%引きで購入しているので、比較してみました。速度の計測には「time」コマンドで行います。

virtualbox v5の場合
tree:~ tree$ time docker-machine create --driver virtualbox dev
Running pre-create checks...
Creating machine...
Waiting for machine to be running, this may take a few minutes...
Machine is running, waiting for SSH to be available...
Detecting operating system of created instance...
Provisioning created instance...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
To see how to connect Docker to this machine, run: docker-machine env dev

real	0m52.265s
user	0m0.226s
sys	0m0.142s
VMWareFusion pro v8の場合
tree:~ tree$ time docker-machine create --driver vmwarefusion dev
Running pre-create checks...
Creating machine...
Waiting for machine to be running, this may take a few minutes...
Machine is running, waiting for SSH to be available...
Detecting operating system of created instance...
Provisioning created instance...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
To see how to connect Docker to this machine, run: docker-machine env dev

real	0m37.940s
user	0m0.294s
sys	0m0.131s

virtualboxが52秒なのに対し、VMWareは37秒で作成できました。今回はpro版なので、最も安価なVMwareFusionの場合はもう少し遅くなると思いますが、恐らくVMWareの方が平均して高速だと思われます。

ホストOSの作成だけでなく、コンテナ上でのアプリケーション速度もVMWareの方が速いんじゃないかと思います。
qiita.com

快適に操作したいなら、お金出してVMWareFusion(できればpro版)の方がいいかもしれませんね。

便利な使い方

便利といえるか怪しいですが、私の場合はローカルのmacのdocker-machineでmysql専用ホストを用意しています。

mysqlホスト上に、MySQL v5.5, v5.6, v5.7 の3つのバージョンを用意しています。業務では複数のMySQLを使うプロジェクトがあり、それぞれバージョンが異なる場合が多々有ります。実際の業務では色々なプロジェクトが複数のバージョンのMySQLが使われている事が多いので、全バージョン揃っていると何かと便利です。

雑感

まだ作成するコンテナが1個なのでdocker runで頑張れますが、コンテナが増えてくるともう訳が分からなくなってきます。その場合はdocker-composeを使う事になりますが、それはまた今度ということで。

私も最初は「docker?どうせインフラ屋向けのものだろ。developerには不要」とか考えて敬遠してましたが、使ってみると以外と簡単でした。しかしネット上に既にある記事のほとんどは「とりあえずこのコマンドを実行すると何となくうまくいきますよ」的なコマンドを羅列しただけの記事が多いので、「ここでこのコマンドを実行するのはどうして解ったの?」と思ったり「ここでコマンド実行するのは何故?」とか思う事が多かったので、今回記事にしてみました。記事にする事で自分自身の理解も結構深まってきた感じがします。

皆docker! docker!と騒いでいますが、今既にあるオンプレミスでインフラベンダーがインフラを握っている環境では簡単に導入できるものではないので、まずはローカル環境で活用していく方法でdockerに慣れていくといいのかな、と思いました。ローカルで暫く触ってdockerに慣れて、そのうちproduction・qa等の環境はオンプレだけど、社内develop環境はdockerに移行、みたいな感じで徐々にdockerに移行できるのが理想ですね。最終的にインフラベンダーを消し飛ばし、オンプレ環境を脱却してamazon ecs等に移行できれば最高ですが、そこまでいける環境なんて中々無いですよね。新規案件ならできそうですが、既存の保守案件ではまず不可能です。

私はその「現場へのdocker導入は現実に考えて無理」な環境なので、ローカル環境やdevelop環境に導入して抗ってみたいなと思ってます。
www.bunkei-programmer.net

docker-compose用の記事も書きましたよ!!

これでMySQLサーバ v5.5, 5.6, 5.7 を docker-compose up するだけで作成できちゃいます!!
www.bunkei-programmer.net