LoginSignup
21
19

More than 5 years have passed since last update.

boot2dockerで公式のmysqlやmongoが起動しない問題(boot2dockerの999問題をちゃんと理解しよう)

Last updated at Posted at 2015-05-07

boot2dockerで公式のmysqlイメージやmongoイメージを起動するときに、run -vオプションの左辺で/Users以下の場所を指定すると起動に失敗します。

数日間うんうん悩んで解決しなかったのですが、Twitterでぼやいてたら答えを教えてもらいました。

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)になっています。
オーナーが自分なのでファイルを作成できたわけです。

なぜ-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に書き込まれることになります。

まとめ

  • 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 さんありがとうございます!!

21
19
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
19