ついにGAになったdocker for macとdocker for windows。これでVirtualboxやVMWareを別途インストールする事なくdockerが利用可能になりましたね!
docker for macですが、既にdocker toolboxでdocker一式をインストールしている状態でも、特に何かをアンインストールする事なくdocker for macをインストールすれば、途中でマイグレーションする?と聞かれてそのままdocker-machineからdocker for macに移行できます。
という事で早速試してみたのですが、MySQLのコンテナにリモートで接続しようとして、ちょっと困った事が起きました。
MYSQLコンテナにつながらない!?
接続するためのMySQLコンテナですが、主要なmysql・mariadbのコンテナを一括生成するdocker-compose関連ファイル一式を既に用意してあります。
github.com
今回はこれを使って、今までのようなdocker-machine上のdockerホストではなく、macのローカルのdockerホストにdocker composeしてみます。
docker-machineを使ってしまうと今までのようにVirtualboxやVMWarefusion等が必要になってしまうため、docker for macでxhyveを使ってVirtualbox・VMWarefusion無しでdockerを動かします。
MySQLコンテナを起動する
まずは前述のファイル群をcloneします。
tree:test tree$ git clone https://github.com/treetips/docker-compose-all-mysql.git Cloning into 'docker-compose-all-mysql'... remote: Counting objects: 20, done. remote: Total 20 (delta 0), reused 0 (delta 0), pack-reused 19 Unpacking objects: 100% (20/20), done. Checking connectivity... done.
中身はこんな感じです。
tree:test tree$ cd docker-compose-all-mysql/ tree:docker-compose-all-mysql tree$ ll total 56 -rw-r--r-- 1 tree wheel 2.7K 7 30 16:26 README.md -rwxr-xr-x 1 tree wheel 110B 7 30 16:26 connect-mariadb-10.0.sh -rwxr-xr-x 1 tree wheel 110B 7 30 16:26 connect-mariadb-10.1.sh -rwxr-xr-x 1 tree wheel 110B 7 30 16:26 connect-mysql-5-5.sh -rwxr-xr-x 1 tree wheel 110B 7 30 16:26 connect-mysql-5-6.sh -rwxr-xr-x 1 tree wheel 110B 7 30 16:26 connect-mysql-5-7.sh -rw-r--r-- 1 tree wheel 1.3K 7 30 16:26 docker-compose.yml drwxr-xr-x 3 tree wheel 102B 7 30 16:26 mariadb10.0 drwxr-xr-x 3 tree wheel 102B 7 30 16:26 mariadb10.1 drwxr-xr-x 3 tree wheel 102B 7 30 16:26 mysql5.5 drwxr-xr-x 3 tree wheel 102B 7 30 16:26 mysql5.6 drwxr-xr-x 3 tree wheel 102B 7 30 16:26 mysql5.7
では全MySQLコンテナを起動します。沢山イメージをダウンローするのでちょっと時間かかります。
tree:docker-compose-all-mysql tree$ docker-compose up -d
Creating mariadb10.1
Creating mysql5.6
Creating mysql5.5
Creating mariadb10.0
Creating mysql5.7
起動したコンテナを見てみます。
tree:docker-compose-all-mysql tree$ docker-compose ps Name Command State Ports -------------------------------------------------------------------------- mariadb10.0 docker-entrypoint.sh mysqld Up 0.0.0.0:3310->3306/tcp mariadb10.1 docker-entrypoint.sh mysqld Up 0.0.0.0:3311->3306/tcp mysql5.5 docker-entrypoint.sh mysqld Up 0.0.0.0:3355->3306/tcp mysql5.6 docker-entrypoint.sh mysqld Up 0.0.0.0:3356->3306/tcp mysql5.7 docker-entrypoint.sh mysqld Up 0.0.0.0:3357->3306/tcp
Portsに書いてある0.0.0.0は特殊な外部に全公開するIPで、localhostや127.0.0.1で接続が可能な状態です。(後述で0.0.0.0についての説明を追記しました)
0.0.0.0がlocalhostで接続できるなら、一見以下で接続できそうな気がしますね。localhostであれば「-h」でホスト指定は不要な筈です。
mysql -uworker -pworker -Dwork
しかしこの結果は以下です。
tree:docker-compose-all-mysql tree$ mysql -P3357 -uworker -pworker -Dwork mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
エラーを見ると、どうやらMySQLコンテナ上のMySQLに接続しにいっているのではなく、macのローカルのMySQLに接続しようとしているようです。
ではIP指定ならどうでしょう。
tree:mysql tree$ mysql -h127.0.0.1 -P3357 -uworker -pworker -Dwork 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 2 Server version: 5.7.13 MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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>
いけました。MySQLコンテナ上のMySQL5.7に接続できました。
ついでにDHCPで振られたIP指定ならどうでしょう。
tree:mysql tree$ mysql -h$(ipconfig getifaddr en1) -P3357 -uworker -pworker -Dwork 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 3 Server version: 5.7.13 MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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>
これもOKですね。どうやら localhost だけ、挙動が異なるようです。
何故localhostではダメなのか
root@5124e62261a5:/# cat /etc/mysql/my.cnf ・・・中略・・・ [mysqld] skip-host-cache skip-name-resolve
恐らくですが、MySQL公式Dockerfileから生成されるmy.cnfに「skip-name-resolve」がハードコードで設定されているため、DNS逆引きが行わず、localhostと127.0.0.1は別物として扱われたため、macのローカルのMySQLに接続しにいっていると思われます。
試しに以下のように変えようとしてもread onlyだと怒られてしまいました。rootユーザで行っても同様です。
mysql> set global skip_name_resolve = 'OFF'; ERROR 1238 (HY000): Variable 'skip_name_resolve' is a read only variable
mysqlの起動オプションに「--disable-skip-name-resolve」というものがあって、mysqldを起動する時に指定する事で「skip-name-resolve」をオフにできるようですが、my.cnfや環境変数で変更できないのはちょっと嫌ですね。
my.cnfを指定したmysql接続
ならば、IP・PORT・ユーザID・パスワード等を気にしなくていい接続の仕方をすればいいのです。
これには2通りあります。
解決策1) --defaults-group-suffix を使う
このオプションは、接続情報を ~/.my.cnf に記述しておくものです。具体的には以下のように使用します。
cat << EOF > ~/.my.cnf [client_mysql5.7] host=127.0.0.1 port=3357 database=work user=worker password=worker EOF chmod 600 ~/.my.cnf
この .my.cnf が有る状態で以下のようにコマンドを実行すると、MySQLコンテナに接続できるようになります。
mysql --defaults-group-suffix=_mysql5.7
こうすれば前述のホストにIP指定するのが面倒臭いよ問題と、mysqlコマンド実行時の以下の警告の抑制を、同時に解決する事ができます。
mysql: [Warning] Using a password on the command line interface can be insecure.
「[client_mysql5.7]」というセクションは複数記述する事ができるので、各mysqlの分だけ用意すれば、全て接続でアカウント情報無しで接続できるようになります。
解決策2) --defaults-extra-file を使う
一見すると「--defaults-group-suffix」ってホームディレクトリに配置するし、パーミッションも600で安全だし、隠しファイルだし、もしかして完璧?と思うかもしれませんが、弱点があります。
それは「ホームに配置する=git等でバージョン管理し難い」という点です。
「--defaults-extra-file」を使う場合は、my.cnfのファイルパスを指定する事で、mysqlに接続できるようになります。このmy.cnfはどこに配置しても構わないというメリットがあります。勿論ファイル名も「my.cnf」で無くても構いません。
「--defaults-extra-file」で使うmy.cnfは「--defaults-group-suffix」の場合と少し異なり、clientセクションにグループを設定する事はできず、「client」固定です。もし複数の接続が指定したい場合は、ファイルを分ける事で対応できます。
cat << EOF > ~/my5.7.cnf [client] host=127.0.0.1 port=3357 database=work user=worker password=worker EOF chmod 600 ~/my5.7.cnf
最終的に、以下のコマンドでMySQLコンテナに接続できるようになります。
mysql --defaults-extra-file=~/my5.7.cnf
勿論この接続方法の場合も、コマンドライン上でパスワードを指定していないので、以下の警告を抑制する事ができます。
mysql: [Warning] Using a password on the command line interface can be insecure.
--defaults-group-suffix と --defaults-extra-file の比較
--defaults-group-suffix のメリット
- ファイルの場所は常に固定なので探さなくてもいい。
- mysql接続時にいちいちmy.cnfのパスを指定しなくていい。(パスは長くなる事が多い)
- my.cnfを見れば、全てのmysqlの接続先情報が書かれているため一覧性が高い。
--defaults-group-suffix のデメリット
- my.cnfをホームディレクトリに配置するのでgit等でバージョン管理しづらくなる。
- 複数プロジェクトでMySQLを使う場合、1ファイルに全プロジェクト、全ステージの接続情報が書かれてしまう。
--defaults-extra-file のメリット
- my.cnfをどの場所に配置しても構わないので、既存環境に手を入れなくてよくなる。
- my.cnfという名前でなくてもいい。
- my.cnfの配置場所が自由なので、git等でバージョン管理し易い。
- 複数プロジェクトでMySQLを使う場合も、フォルダ・ファイル名を分ける事で綺麗に分離できる。
--defaults-extra-file のデメリット
- my.cnfの場所を知っていなければいけない。
- 起動時にmy.cnfの長いパス名を入力するのが辛い。
両者ともメリット・デメリットはありますね。--defaults-group-suffixの方が手軽ではあるのですが、やはり1ファイルに全プロジェクト・全ステージの接続情報が混在するのは嫌ですね。となると--defaults-extra-fileの方がいいのですが、接続時のパス指定が辛い、と。。。。
というか、--defaults-group-suffix も --defaults-extra-file もオプション名が長くてこの時点で辛いんですが。。。
alias使ってコマンドの短縮化をする事は必須ですね。。。
追記1) MySQLを0.0.0.0で公開させない方法
docker for macでMySQLコンテナを生成してリモート接続する - 文系プログラマによるTIPSブログb.hatena.ne.jp
- [docker]
- [MySQL]
0.0.0.0 はすべて(*)なので 127.0.0.1 などと異なり外部からも繋がっちゃいますね。こちらは 127.0.0.1:3355:3306 という感じで指定するほうがいいかも。localhost に関しては https://yoku0825.blogspot.jp/2013/02/userlocalhostuser127001.html
2016/07/30 18:47
上記コメントを頂きました。(実は事前にこちらのサイトを拝見して、127.0.0.1とlocalhostが別ものになる旨を勉強しました)
今回0.0.0.0:3357でMySQLが起動してしまうのは、docker-compose.ymlでportしか指定していない点にあります。
現在の設定は↓こうです。portは3357:3306です。
mysql5.7: image: mysql:5.7 container_name: mysql5.7 ports: - 3357:3306 environment: - MYSQL_DATABASE=work - MYSQL_USER=worker - MYSQL_PASSWORD=worker - MYSQL_ROOT_PASSWORD=root volumes: - ./mysql5.7/conf.d:/etc/mysql/conf.d
これを、以下のようにします。
mysql5.7: image: mysql:5.7 container_name: mysql5.7 ports: - 127.0.0.1:3357:3306 environment: - MYSQL_DATABASE=work - MYSQL_USER=worker - MYSQL_PASSWORD=worker - MYSQL_ROOT_PASSWORD=root volumes: - ./mysql5.7/conf.d:/etc/mysql/conf.d
この状態でdocker-composeで起動すると、以下のように127.0.0.1:3357で待受してくれるので、全公開状態にならずに済みました。
tree:docker-compose-all-mysql tree$ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------- mariadb10.0 docker-entrypoint.sh mysqld Up 0.0.0.0:3310->3306/tcp mariadb10.1 docker-entrypoint.sh mysqld Up 0.0.0.0:3311->3306/tcp mysql5.5 docker-entrypoint.sh mysqld Up 0.0.0.0:3355->3306/tcp mysql5.6 docker-entrypoint.sh mysqld Up 0.0.0.0:3356->3306/tcp mysql5.7 docker-entrypoint.sh mysqld Up 127.0.0.1:3357->3306/tcp
この件は全公開状態にならないだけであって、前述のlocalhostでdockerホスト上のMySQLに接続できない問題は解決されていません。
雑感
docker-toolboxを卒業するぞ〜 → 10分で躓く、となって早速出鼻をくじかれて悲しかったです。まあdockerの問題ではなくMySQLの公式イメージの問題なのですけどね。
docker for macを使ってみて思ったのですが、これ、docker-machineのようにdockerホストを分ける事ってできませんよね?docker-machineの場合はプロジェクトごとにdockerホストを分ける事ができるので、環境を分離できて楽だったのですよね。dockerホストが単一だとすると複数のプロジェクトのコンテナが1ホストにダラーっと並んでしまう気がするのですが、そういうものですかね。
複数ホストで運用したい場合は手軽なローカルのxhyveのdockerホストでなく、docker-machineで今までのようにVirtualboxやVMWarefusion使えって事でしょうか。一応docker-machine用のxhyveドライバを作られている方もいるのでそれを使えばVirtualboxやVMWarefusionが不要になるのですが、あまり話を聞かないのでちょっと心配だな〜、と思っています。
github.com
docker社が今後オフィシャルのxhyveのdocker-machineドライバ作ってくれると嬉しいですね(チラッ