Docker 1.6とdevicemapperの話

Ubuntu 14.04(LTS) + get.docker.io版Docker 1.6で devicemapperを使うとコンテナの起動や削除に時々失敗する現象が発生しました。 (devicemapperがデフォルト。。。)

最近、AWS OpsWorksで アプリケーションをDockerで配布仕組みを実装していて、これが原因でデプロイが失敗 することがありました(幸いまだステージング)。

エラー内容

https://github.com/docker/docker/issues/4036 から引用すると、以下のようなエラーが出力されているとこの問題に該当しています。

Error mounting ‘/dev/mapper/docker-8:1-4980769-56bee8c4da5bd5641fc42405c742083b418ca14ddfb4a3e632955e236e23c284’ on ‘/var/lib/docker/devicemapper/mnt/56bee8c4da5bd5641fc42405c742083b418ca14ddfb4a3e632955e236e23c284’: no such file or directory

さらに、docker infoを実行することで問題のある環境かどうかを判断できます。

docker info | grep -i udev
 Udev Sync Supported: false
 WARNING: No swap limit support

ここで、 Udev Sync Supported がfalseなら該当しています。

対応方法

上記の#4036を読むと、 devicemapperのコードを静的リンクしていると発生するようです。

そこで、DockerをOS側のdevicemapperのライブラリとリンクする ようにビルド(つまり普通にビルドする)するとよさそうです。

workaroundとしてAUFSを使う人もいるようですが、upstream(kernel)サポートが入らないこともあり、 現状では非推奨です(使えるのはUbuntuくらい?)。boot2dockerはまだAUFSのようです。

参考: http://www.projectatomic.io/docs/filesystems/

先日リリースされたUbuntu 15.04に含まれるDocker(1.5)を使う場合は Ubuntu Sync Supported がtrueになっているためこの問題には該当しません。 また、おそらく次回リリース以降はget.docker.io版も動的リンク版になりそうなので、 1.7以降では改善されているかもしれません。

参考: https://github.com/docker/docker/issues/4036#issuecomment-76723060

参考: https://github.com/docker/docker/pull/11412 これによると、1.7以降静的リンクされたDockerでdevicemapperが原則利用できなくなります。

残念ながら、OpsWorksはLTS(14.04など)のみ対応しているのでここでは自分でビルド する方法を紹介します。

Docker自体がDocker内でビルドされているので、この仕組みを利用します。 幸い、このコンテナはUbuntu 14.04をベースにしているので、 私の場合は devicemapperをソースではなく、パッケージ版に修正 するだけで大丈夫です。

この修正ブランチを使ってビルドする方法:

git clone git://github.com/docker/docker.git && cd docker
git fetch git://github.com/nabeken/docker.git issues-4036-dynbinary:issues-4036-dynbinary
git checkout issues-4036-dynbinary

sudo docker build -t docker .

sudo docker run --privileged --name docker -e AUTO_GOPATH=1 -e DOCKER_BUILDTAGS=btrfs_noversion docker ./hack/make.sh dynbinary

sudo docker cp docker:/go/src/github.com/docker/docker/bundles/1.6.0/dynbinary/docker-1.6.0 .
sudo docker cp docker:/go/src/github.com/docker/docker/bundles/1.6.0/dynbinary/dockerinit-1.6.0 .

sudo ./docker-1.6.0 info

ここではまだサーバ側を入れ替えていないため、 Udev Sync Supported はfalseです。

ビルドしたバイナリは最終的にはAMIに入れてしまうのでバイナリを直接差し替えます。

sudo service docker stop
sudo cp /usr/bin/docker{,.orig}
sudo cp ./docker-1.6.0 /usr/bin/docker
sudo cp ./dockerinit-1.6.0 /usr/bin/dockerinit
sudo service docker start
sudo docker info | grep -i udev
sudo: unable to resolve host ip-10-15-15-4
 Udev Sync Supported: true
 WARNING: No swap limit support

Udev Sync Supported: true なのが確認できました。 ビルドには時間が掛かるので2つのバイナリを適当な場所に配置し、packer等でAMIに焼きましょう。

おまけ

https://github.com/nabeken/docker/releases/tag/v1.6.0-issues-4036-dynbinary

(Use at your own risk)