HomebrewからDockerにMySQL環境を移行する

morimorihogeです。ぼちぼち開発現場でもDockerが当たり前に使われている現場が増えてきた印象です。Moby DockかわいいよMoby Dock。

Touch Bar搭載の新型MacBook Pro Retinaに移行したころに、新Macに触る良いテンションの勢いでHomebrew環境のMySQLをDockerに移行してみた時のメモです。
既にQiitaなんかでも同様の事例が多数あると思いますが、備忘録までに。

※ずいぶん前(2016末)に途中まで下書きして寝かせてしまった内容なので、ここ最近では改善されている部分があるかもしれません(主にパフォーマンス面など)

概要

この手順は意識高いDocker勢で推奨されているData Volume Containerを使った方式ではなくVOLUMEオプションを使った方式です。利点、欠点は以下の通りなのでData Volume Containerが良い人は適宜カスタマイズしてください。

  • 利点
    • MySQLのDATA_DIRmy.cnf等の設定ファイルがMac側で直接触れるため、編集・参照しやすい
    • データ類がMacのファイルとして存在するため、バックアップ/リストアしやすい(TimeMachine的にも相性がよさそう)
    • 「うおーなんかよくわからんContainerばっかりになってきたから全部消すか」とかで全containerをdocker rmしてしまってもデータはMac側にあるので安心
  • 欠点
    • Docker for Macは遅いという話がちょいちょい見受けられるので、速度を求める人にはつらそう。参考: Docker for Macが遅い問題をdocker-syncで解決する
    • VOLUME接続しているのでMySQL containerのデータがDockerに閉じなくなってしまうので、コンテナ至上主義者的には許せない人がいそう

一方、以下の点についてはHomebrew環境と同様に利用可能です。

  • HomebrewでインストールするMySQLと同様に、localhost:3306でアクセスできる
  • Mac自体を再起動した後も、当然普通に自動起動できる(いちいちdocker runしなくてよい)

なお、基本的にここでやってることはDocker HubのMySQLオフィシャルイメージのサイトに書いてあることをやっているだけなので、特にテクい技術は使っていません。あしからず。

旧環境のMySQLをdump

普通にmysqldumpでどうぞ。僕の場合はDBが多数ありすぎたので古いものはアーカイブするために、一度個別のテーブルごとファイルに出しました。

mysqldump -uroot -p"${password}" db_1 > db_1.dump
mysqldump -uroot -p"${password}" db_2 > db_2.dump
mysqldump -uroot -p"${password}" db_3 > db_3.dump
mysqldump -uroot -p"${password}" db_4 > db_4.dump
mysqldump -uroot -p"${password}" db_5 > db_5.dump

みたいなスクリプトをdump.shとかの名前で保存して

mkdir backups
cd backups
bash ../dump.sh

とかで出ます。この辺は普段からMySQL使っている人たちには今更だと思います。

旧環境のmy.cnfを持ってくる

MySQLで大事なのはmy.cnfの設定です。innoDBのチューニング設定やutf8mb4対応向けのconfigなど、デフォルトのmy.cnfだと使用に耐えない部分をカスタマイズした泥臭いmy.cnfを新環境にコピーしておきます。

Docker向けのデータ領域を作成する

VOLUMEオプションで接続する用のファイル置き場を作成します。
なんとなく僕は~/docker/#{サービス名}/#{VOLUMEで繋ぐディレクトリ}という感じでファイルを置くようにしているので、以下の様なディレクトリツリーでmkdirしました。
VOLUMEの接続用ディレクトリはどんな名前でも構いませんが、containerにdocker execでbash接続したとき等に迷わないのでcontainer内のどのパスに接続されているのかがある程度分かりやすい名前が良いと思います。

$ tree -L 2 ~/docker
docker
└── mysql
    ├── etc_mysql_conf.d
    └── var_lib_mysql

上記見てもらえればなんとなくわかるかと思いますが、これからdocker pullするmysqlというコンテナについて、

  • Mac側の~/docker/mysql/etc_mysql_conf.dをcontainerの/etc/mysql/conf.dに接続
  • Mac側の~/docker/mysql/var_lib_mysqlをcontainerの/var/lib/mysqlに接続

という形で接続していきます。

MySQLサーバコンテナを起動する

というわけで、MySQLのサーバコンテナを起動します。ここで、サーバコンテナは後々よく指定することになるので--nameオプションで名前をつけると便利です。ここではmysql-serverという名前で立ち上げます。
その他、先ほど作成した~/docker/mysql以下のディレクトリに対してVOLUMEオプションで繋ぎこみ、port 3306をlocalhostに接続する設定を追加し、MySQL 5.7 containerを以下のコマンドで起動します(他のバージョンがほしい人は適宜修正して下さい)。

docker run --name mysql-server \
 -v ~/docker/mysql/etc_mysql_conf.d:/etc/mysql/conf.d \
 -v ~/docker/mysql/var_lib_mysql:/var/lib/mysql \
 -e MYSQL_ROOT_PASSWORD='root_password' \
 -p 3306:3306 \
 -d mysql:5.7

これで、MySQLのconfig及びデータファイルはMac側のファイルシステムにそのまま置きつつMySQL containerを起動することができます。
docker run オプションに関するざっとした解説は以下の通りです。

  • --name : 起動したコンテナに任意の名前を付ける。この後別containerから参照するときに使うので、サービス系のcontainerには任意名を付けると良いです
  • -v, --volume : Docker HostContainerのファイルシステムを共有する。通常VirtualBox等でDocker HostのVMを起動している場合、Host OS側のファイルシステムはNFSやSamba共有しないと参照できないが、Docker for MacはHypervisor.frameworkを使うxhyveを利用しているので、 ホスト側Macのディレクトリをそのままvolumeオプションで繋ぐことができる。複数のvolumeを接続したい場合、例の様に複数-vオプションを付ければ良い
  • -e, --env : containerに環境変数を割り当てることができる。公開されているDocker Imageで、パスワードやアクセスキーなど、コンテナ起動時に設定したい情報は-eオプションで設定するように作られていることが多い
  • -p, --publish : containerのポートをDocker Hostのポートにbindingし、Docker Host側からcontainerにポート経由でアクセスできるようにする。Docker Host側(今回はMac)のwell knownポートを使う場合はroot権限が必要
  • -d : 引数を持たないオプション。コンテナをバックグラウンド実行する。起動しっぱなしになるサービス系のコンテナではこれを付けると良い

これであとはlocalhost:3306にアクセスすればMySQLにアクセスすることができます。

サーバコンテナを自動起動させる

開発機の場合、カジュアルに再起動したりするため、毎回docker runコマンドを実行するのはおっくうです。そこで、--restart alwaysオプションを付けます。

このオプションを付けることで、Docker Daemonが起動したら直ちに当該containerが起動しますし、何らかの原因でcontainerが終了しても勝手に再起動してきます。
containerの設定中にこのオプションを付けてしまうと起動 -> 停止を繰り返して面倒なことになりますが、ある程度安定して実行できる環境整備が終わったらこのオプションを付ければ、再起動しても勝手にサービスが上がってくるようになるのでDockerを意識しないで使うことができるようになります。

サーバコンテナの設定を確認する

トラブルシューティング用途でcontainerの設定を見たくなることがありますが、そんなときはdocker execを使い、

docker exec -it mysql-server bash

とすればシェルが取れます。-itオプションを忘れないようにしましょう。

バックアップを取り込む

無事安定してMySQLコンテナが起動するようになったら、取り込みを行いましょう。ここからは既にlocalhost:3306で普通にMySQL接続できる状態になっていますので、GUIツールなどに慣れてる人はTCP経由で取り込むことも可能です。
いや、俺は最後までDockerでやるんだ!という人は、

docker run --rm -i mysql:5.7 sh -c 'exec mysql -h "mysql-server" -uroot \
 -p"root_password"' <  DUMP_DATA.dump

といった感じで取り込み実行することが可能です。ここでは既に起動しているmysql-server containerとは別に、使い捨てのMySQLクライアントコンテナを実行しています(--rmオプションはプロセス終了時にcontainerが保存されない)。
この方式のメリットは、ローカル環境に当該バージョンのMySQLクライアントライブラリが無くても使える点です。これこそDockerの正統な使い方という感じしますね。

おまけ:GUIのKitematicを使う

DockerはCUIで使うのが基本ではありますが、ローカル開発環境の場合、GUIも欲しいという人もいると思います。
Kitematic は地味に更新を続けていて、Containerの設定やコンソールログを見る程度の用途であれば充分実用の範囲なので、試してみる価値はあると思いますよ。

まとめ

今回は塩漬けにしていた記事からDockerのMySQL環境を構築する方法についてまとめました。
Docker for MacのBetaが出てから本環境に移行して数多くのシステム開発をこなしていますが、間にDocker for Macのアップグレード等を挟みつつも特に問題なく1年以上使えているので開発環境レベルということであれば安定している環境と言えるのではないかと思います。

Dockerはまだ早い、Dockerは難しいという方もいますが、正直な所この手の技術は使わないと一生使えるようにならないので、なんとか使うタイミングを作って練習していくしかないのではないかと思います。
VirtualBoxでええやん、という人もいますが、一度Docker Containerの起動の速さに慣れてしまうとVirtualBox/VMWareには戻れないくらいの感覚の差があります。

ではでは、皆様良いContainerライフを。

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

morimorihoge

高校卒業後,学生をやりながらずっとWebアプリ開発に携わってきました.2010くらいまではPHP/Symfonyプログラマでしたが,それ以降のWeb開発はRailsほぼ一本に宗旨替えしました.開発とは別にサーバ構築・運用も10年以上やってきているので,要件定義から設計・実装・環境構築・運用まで一通り何でもこなせます.開発以外では季節により大学でWebサービス開発やプログラミング関連の非常勤講師もしており,技術の啓蒙・教育にも積極的に関わっています.最近はPM的な仕事が増えていますが,現役開発者としていつでも動ける程度にはコードもサーバも弄る日々を送っています.AWS 認定ソリューションアーキテクト – アソシエイトレベル取りました

morimorihogeの書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ