boot2dockerで公式のmysqlイメージやmongoイメージを起動するときに、run -v
オプションの左辺で/Users
以下の場所を指定すると起動に失敗します。
数日間うんうん悩んで解決しなかったのですが、Twitterでぼやいてたら答えを教えてもらいました。
boot2dockerでmysqlコンテナを起動しようとしたら、volumeのマウントでこける...ぐぬぬ InnoDB: The error means mysqld does not have the access rights to Ithe directory.
— docker run DQNEO (@DQNEO) April 23, 2015
@DQNEO 突然失礼します。boot2docker の環境で、-v /Users/...:/var/lib/mysql とすると、/var/lib/mysql が id 1000 の所有になるので mysql ユーザー(id 999)では起動できなくなります
— mapk0y (@mapk0y) April 26, 2015
tl;dr
- boot2dockerは当初は-vが使えなかったが、Docker1.3から使えるようになった。
- ところが、vboxsf(=Virtualbox Guest Additions)の仕組みを使っているので、制約がある。
- 公式のmysqlイメージやmongoイメージを起動するときに
run -v $(pwd):
とかするとその制約にひっかかる。
docker run -v ~/tmp/mysql:/var/lib/mysql でこける
$ docker run -v ~/tmp/mysql:/var/lib/mysql --rm --name tmp -it -e MYSQL_ROOT_PASSWORD=foo mysql
Running mysql_install_db ...
Installing MySQL system tables...2015-05-07 10:30:39 0 [Note] /usr/sbin/mysqld (mysqld 5.6.24) starting as process 14 ...
2015-05-07 10:30:39 14 [Note] InnoDB: Using atomics to ref count buffer pool pages
2015-05-07 10:30:39 14 [Note] InnoDB: The InnoDB memory heap is disabled
2015-05-07 10:30:39 14 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2015-05-07 10:30:39 14 [Note] InnoDB: Memory barrier is not used
2015-05-07 10:30:39 14 [Note] InnoDB: Compressed tables use zlib 1.2.7
2015-05-07 10:30:39 14 [Note] InnoDB: Using Linux native AIO
2015-05-07 10:30:39 14 [Note] InnoDB: Not using CPU crc32 instructions
2015-05-07 10:30:39 14 [Note] InnoDB: Initializing buffer pool, size = 128.0M
2015-05-07 10:30:39 14 [Note] InnoDB: Completed initialization of buffer pool
2015-05-07 10:30:39 7f0175bcc720 InnoDB: Operating system error number 13 in a file operation.
InnoDB: The error means mysqld does not have the access rights to
InnoDB: the directory.
2015-05-07 10:30:39 7f0175bcc720 InnoDB: Operating system error number 13 in a file operation.
InnoDB: The error means mysqld does not have the access rights to
InnoDB: the directory.
2015-05-07 10:30:39 14 [ERROR] InnoDB: Creating or opening ./ibdata1 failed!
2015-05-07 10:30:39 14 [ERROR] InnoDB: Could not open or create the system tablespace. If you tried to add new data files to the system tablespace, and it failed here, you should now edit innodb_data_file_path in my.cnf back to what it was, and remove the new ibdata files InnoDB created in this failed attempt. InnoDB only wrote those files full of zeros, but did not yet use them in any way. But be careful: do not remove old data files which contain your precious data!
2015-05-07 10:30:39 14 [ERROR] Plugin 'InnoDB' init function returned error.
2015-05-07 10:30:39 14 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2015-05-07 10:30:39 14 [ERROR] Unknown/unsupported storage engine: InnoDB
2015-05-07 10:30:39 14 [ERROR] Aborting
2015-05-07 10:30:39 14 [Note] Binlog end
2015-05-07 10:30:39 14 [Note] /usr/sbin/mysqld: Shutdown complete
こけました(´・ω・`)
docker run -v ~/tmp/db:/data/db mongo でこける
$ docker run --rm -it -v ~/tmp/db:/data/db mongo
2015-05-07T10:31:09.234+0000 I STORAGE [initandlisten] exception in initAndListen: 98 Unable to create/open lock file: /data/db/mongod.lock errno:13 Permission denied Is a mongod instance already running?, terminating
2015-05-07T10:31:09.234+0000 I CONTROL [initandlisten] dbexit: rc: 100
こけました(´・ω・`)
"-v /tmp"なら動く
ところが、"-v ~/tmp/" としていたものを"-v /tmp/" に変えてみると、あーら不思議!ちゃんと起動するじゃありませんか。
mongo
docker run -it -v /tmp/db:/data/db mongo
mysql
docker run -it -v /tmp/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=foo mysql
これはいったいどういうことなのでしょうか??
最小構成で実験してみる
このエラーを再現する最小のDockerイメージを作ってみましょう。
FROM debian:wheezy
RUN groupadd -r mysql && useradd -r -g mysql mysql
VOLUME /var/lib/mysql
mysql
という名前のユーザを作ってVOLUME設定するだけのDockerfileを作りました。
これをビルドします。
$ docker build -t mysqltest .
ビルドできたらrunしてコンテナ内に入ってみましょう。
$ docker run --rm -it -v ~/tmp/mysql:/var/lib/mysql mysqltest bash
root@7eef14174f04:/#
mysqlという名のユーザにスイッチして、ファイル作成を試みます。
root@7eef14174f04:/# su - mysql
No directory, logging in with HOME=/
$ touch /var/lib/mysql/file
touch: cannot touch `/var/lib/mysql/file': Permission denied
おぉ!失敗しました。
ディレクトリに対するパーミッションがないからファイルを作れないというエラーのようです。
公式のmysqlやmongoイメージが起動しなかったのはどうもこれが原因のようです。
パーミッション関係の情報を見てみましょう。
$ id
uid=999(mysql) gid=999(mysql) groups=999(mysql)
$ stat /var/lib/mysql
File: `/var/lib/mysql'
Size: 68 Blocks: 0 IO Block: 4096 directory
Device: 1bh/27d Inode: 42 Links: 1
Access: (0755/drwxr-xr-x) Uid: ( 1000/ UNKNOWN) Gid: ( 50/ staff)
Access: 2015-05-07 13:48:22.000000000 +0000
Modify: 2015-05-07 13:48:22.000000000 +0000
Change: 2015-05-07 13:48:22.000000000 +0000
まず自分はmysql(id=999)という名前のユーザです。
それに対して/var/lib/mysql
ディレクトリの所有者は名無しさん(uid=1000)であり、所有グループはstaff(gid=50)、ディレクトリのパーミッションは0755です。
たしかにこれではファイル作成ができませんね。
ここで、「じゃあディレクトリのパーミッションを0777にすればいいんじゃね?」と考えて
# 一度rootに戻って
$ exit
# パーミッションを変更してみる
root@7eef14174f04:/# chmod 0777 /var/lib/mysql
root@7eef14174f04:/# stat /var/lib/mysql
File: `/var/lib/mysql'
Size: 68 Blocks: 0 IO Block: 4096 directory
Device: 1bh/27d Inode: 42 Links: 1
Access: (0755/drwxr-xr-x) Uid: ( 1000/ UNKNOWN) Gid: ( 50/ staff)
Access: 2015-05-07 13:48:22.000000000 +0000
Modify: 2015-05-07 13:48:22.000000000 +0000
Change: 2015-05-07 13:48:22.000000000 +0000
Birth: -
あれ?パーミッションを変更できませんでした。(´・ω・`)
つまりこの方法ではどうやってもファイルを作成できないようです。
-v /tmp/mysql:
だとどうか
さっきのコンテナを一度破棄して、
ボリュームオプションの左辺を-v /tmp/mysql:
として起動してみます。
$ docker run --rm -it -v /tmp/mysql:/var/lib/mysql mysqltest bash
root@e95453eda187:/# su - mysql
No directory, logging in with HOME=/
$ touch /var/lib/mysql/file
$ ls /var/lib/mysql/file
/var/lib/mysql/file
あれ!今度はあっさり成功しました。
何が違うんでしょうか?
パーミッション周りを見てみましょう。
$ id
uid=999(mysql) gid=999(mysql) groups=999(mysql)
$ stat /var/lib/mysql
File: `/var/lib/mysql'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 801h/2049d Inode: 1062117 Links: 4
Access: (0755/drwxr-xr-x) Uid: ( 999/ mysql) Gid: ( 999/ mysql)
Access: 2015-05-07 13:37:55.844312758 +0000
Modify: 2015-05-07 14:01:38.951754264 +0000
Change: 2015-05-07 14:01:38.951754264 +0000
Birth: -
/var/lib/mysqlの所有者がmysql(id=999)
になっています。
オーナーが自分なのでファイルを作成できたわけです。
@mapk0y あ!!なるほど、だから -v /tmp/mysql:/var/lib/mysql だと動いたんですね。そうかそうかー やっと気づきました。ありがとうございます!!
— docker run DQNEO (@DQNEO) April 26, 2015
なぜ-v ~/tmp
と-v /tmp
で挙動が違うのか?
答えはboot2dockerの仮想マシンの中にあります。
仮想マシンの中に入ってマウント情報を見てみましょう。
$ boot2docker ssh
docker@boot2docker:~$ mount
[中略]
none on /Users type vboxsf (rw,nodev,relatime)
そうなのです。
boot2dockerでは、ホストマシン(Mac)の/Usersをゲストマシンの/Usersにマウントしているのです。そしてこのマウント方法にvboxsf
(=Virtualbox Guest Additions)というちょっとややこしい仕組みが使われているのです。
詳しくはこちら:boot2dockerでのVolume問題が解決しそう
-v /tmp/mysql:
の場所について
-v /tmp/mysql:
だと動くと書きましたが、ここでも注意が必要です。
この/tmp
はホストマシン(Mac)のディレクトリではなくてboot2dockerの仮想マシン内の/tmp
を指しているのです。
つまり、mysqlのデータは仮想マシン内の/tmp/mysql
に書き込まれることになります。
@DQNEO そうですね。特に、/Users 以下を何気なく指定してると透過的に見えちゃいますからね...。boot2docker が使いやすくしてくれてる分、少し使い込むと他のところではまりやすくなってるのがちょっと残念です
— mapk0y (@mapk0y) April 26, 2015
まとめ
- boot2dockerが透過的な存在だと思ったらダメです。
- boot2dockerはむしろVagrantと同じようなツールだと考えるべき
- むしろboot2dockerを使わずにVagrantでやったほうがハマりにくいかもしれない。
参考
検索するとissueがいっぱい出てきますが根っこは全部同じのようでした。
https://github.com/boot2docker/boot2docker/issues/581
https://github.com/boot2docker/boot2docker/issues/587
https://github.com/docker-library/mysql/issues/44
https://github.com/docker-library/mongo/issues/30
謝辞
@mapk0y さんありがとうございます!!