DockerのストレージバックエンドにBtrfsが使えるようになってたので試した

みなさんこんにちは。 最近Docker Meetup in Tokyo #1の参加を逃したりImmutable Infrastructure Conference #1の参加申し込みに出遅れたりしてがっくりしている@r_takaishiです。

さて、今回はDockerのv0.8でストレージドライバに新しくBtrfsが追加されたので、これを試してみました。

Btrfsをストレージとして使うための準備

まずは、DockerがBtrfsをストレージとして使えるようにします。 なお、環境ですが、Vagrant + Ubuntu13.10 を使用しました。 Dockerのインストールは公式ドキュメントに従っています。 Btrfsを使うための手順は以下の通りです。

  1. Btrfsなパーティションを作成 & マウントする
  2. Dockerデーモンの起動オプションでストレージドライバとデータ保存先のディレクトリを指定する
  3. Dockerデーモンを再起動する

Btrfsなパーティションを作成 & マウントする

適当にストレージを追加して、mkfs.btrfsでファイルシステムを作成、任意のディレクトリにマウントするだけです。 今回は、「/opt/docker」にマウントしておくことにします。

Dockerデーモンの起動オプションでストレージドライバとデータ保存先のディレクトリを指定する

Dockerのデーモンは標準だとストレージドライバにaufsを、データの保存先には「/var/lib/docker」を使用します。 これを、ストレージドライバにbtrfsを、データの保存先には「/opt/docker」を使用するように設定してあげます。 サービスとして起動しているので、その設定ファイルである「/etc/default/docker」内の「DOCKER_OPTS」を以下のように書き換えます。

[bash]
DOCKER_OPTS="-s btrfs -g /opt/docker"
[/bash]

Dockerデーモンを再起動する

再起動しましょう。これで、ストレージドライバにBtrfsを使うようになります。

[bash]
sudo service docker restart
[/bash]

aufsとbtrfsで、コンテナのビルド速度を比較する

Btrfsストレージドライバを触っている時、ビルドに時間がかかるような気がしたので、aufsと比較してみることにしました。 比較する操作は以下の通り。

  1. ubuntu:13.10をベースにイメージを作成(ubuntu:13.10はあらかじめpullしておきます)
  2. 1で作成したイメージをベースにイメージを作成
  3. 2で作成したイメージをベースにイメージを作成
  4. 2〜3を100回繰り返す

これらの操作を行うスクリプトをRubyで書き、1〜4に要する時間を測定しました(測定回数は一応5回)。 その結果、以下のように大きな差がありました。

  • Btrfs:平均256秒
  • aufs: 平均47秒

実に5倍の差があります。現時点で、Btrfsストレージドライバは実験的なものではあるのですが、これ程差があるとは思いませんでした。 仮想マシンを作成する事に比べるとはるかに高速ですが、それでもインフラをCIするような、ビルドを何度も繰り返すことになるケースだと遅く感じる事がありそうです。 今の所aufsの使用で困っている事はないので、Btrfsストレージドライバをメインに使うのはしばらく先にしようと思います。 Btrfsストレージドライバが遅い理由までは今回は調べることはできていません。現状の実装の影響なのか、そもそも仕組みからして遅い、という可能性もあります。 後、これもきちんとは調べていないのですが、aufsで100個近くヒストリを繋いでいると、後半にいくにつれて若干ビルドに時間がかかるようになっていたような気がします。 今後、調べてみたいですね。

備考

測定に使用したスクリプトは以下の通りです。出力が汚いけど気にしない。

 

[ruby]
— coding: utf-8 —

require ‘benchmark’ require ‘systemu’

5.times do |count|
# Btrfs用。作成したイメージ等を全削除する。 #sudo service docker stop #cd /opt/docker && sudo btrfs subvolume list . | awk ‘{print $9}’ | xargs -I{} sudo btrfs subvolume delete {} #sudo rm -rf /opt/docker/*
# aufs用。作成したイメージ等を全削除する。 sudo docker images | awk ‘{print $3}’ | xargs -I{} sudo docker rmi {} sudo service docker stop sleep 2 sudo rm -rf /var/lib/docker
# サービスの起動と初期イメージの取得 sudo service docker start sleep 2 systemu "sudo docker pull ubuntu:13.10"
# ビルドの繰り返し(ここの時間を測定) Benchmark.bm do |x| x.report("#{count}: ") { base_id=” status, stdout, stderr = systemu "echo ‘FROM ubuntu:13.10\nRUN echo init >> /log’ | sudo docker build -t base -" stdout.each_line do |line| if line =~ /Successfully built (.*)\n/ base_id=$1 end end

100.times do |num|
status, stdout, stderr = systemu "echo ‘FROM #{base_id}\nRUN echo #{num} >> /log’ | sudo docker build -t #{num} -"
stdout.each_line do |line|
# puts line
if line =~ /Successfully built (.*)\n/
base_id=$1
end
end
end
end
[/ruby]