LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第20回LXCの構築・活用 [6] ─いろいろなストレージバックエンドの利用(2:Btrfs)

前回はLXCでサポートされているストレージバックエンドのうち、重ねあわせのできるUnion Filesystemであるoverlayfsとaufsを使ったクローンを紹介しました。

今回も引き続きLXCがサポートしているストレージバックエンドを使ったLXCの使用方法を紹介していきます。

今回はBtrfsをストレージバックエンドとして使う場合を取り上げましょう。なお、ここではBtrfsが持つ詳細な機能や操作については説明しません。Btrfsについては公式サイトなどの文書を参考にしてください。

Btrfsをストレージバックエンドとして使う場合の準備

BtrfsをLXCコンテナのストレージバックエンドとして使う場合には準備が必要です。

当然、コンテナの保存場所として使うディレクトリがBtrfs上になければいけませんので、まずはBtrfsで構築された領域が必要ですね。

$ sudo apt-get install btrfs-tools (Btrfs用のツールをインストール)
$ sudo mkfs -t btrfs /dev/vdc1 (Btrfsファイルシステムの作成)

ここの例ではパーティション/dev/vdc1をBtrfs用に利用しています。

LXC 1.0系列を使う場合の準備

LXC 1.0系列を使っている場合は、Btrfsの領域を準備したあと、ちょっとした準備が必要な場合があります。この準備はlxc-snapshotコマンドを使ってコンテナのスナップショットを作成する場合に必要です。lxc-snapshotを使わないのであれば特に以下で紹介する操作は不要です。

lxc-snapshotコマンドは、ストレージバックエンドとしてBtrfsを使っているコンテナの場合、Btrfsのスナップショット機能を使ってコンテナのスナップショットを作成します。このスナップショットはコンテナの保存場所が/var/lib/lxcの場合は/var/lib/lxcsnaps以下に保存されます。

たとえばコンテナ名がct01の場合、スナップショットは/var/lib/lxcsnaps/ct01以下に保存されます。

Btrfsでその領域のスナップショットを保存するにはスナップショット先も同じボリューム上になくてはいけませんので、たとえば/var/lib/lxcを独立したBtrfsでマウントしているような場合は/var/lib/lxcsnapsへスナップショットを保存できません。

そこで/var/lib/lxc/var/lib/lxcsnapsを同じBtrfs配下のサブボリュームとして準備しておく必要があります。

$ sudo mount /dev/vdc1 /mnt (作成したBtrfsを一旦/mntにマウント)
$ cd /mnt
$ sudo btrfs sub create lxc (lxcという名前でサブボリュームを作成)
$ sudo btrfs sub create lxcsnaps (lxcsnapsという名前でサブボリュームを作成)
$ sudo mkdir /var/lib/lxcsnaps (lxcsnapsディレクトリの作成)
$ sudo mount -o subvol=lxc /dev/vdc1 /var/lib/lxc
(サブボリュームlxcを/var/lib/lxcにマウント)
$ sudo mount -o subvol=lxcsnaps /dev/vdc1 /var/lib/lxcsnaps
(サブボリュームlxcsnapsを/var/lib/lxcsnapsにマウント)

上記の例では/dev/vdc1に作成したファイルシステムを一旦/mntにマウントしたあとで、サブボリュームとしてlxclxcsnapsを作成しています。

そして、マウントはそれぞれのサブボリュームをマウントするようにします。これで同じボリューム上に/var/lib/lxc/var/lib/lxcsnapsが存在しますので、/var/lib/lxc以下のサブボリュームを/var/lib/lxcsnapsにスナップショットできます。

マウントできることが確認できたら、/etc/fstabに記述しておきましょう。

$ echo "/dev/vdc1 /var/lib/lxc btrfs subvol=lxc 0 0" \
> | sudo tee -a /etc/fstab
/dev/vdc1 /var/lib/lxc btrfs subvol=lxc 0 0
$ echo "/dev/vdc1 /var/lib/lxcsnaps btrfs subvol=lxcsnaps 0 0" \
> | sudo tee -a /etc/fstab
/dev/vdc1 /var/lib/lxcsnaps btrfs subvol=lxcsnaps 0 0

これでホストOSをリブートしても/var/lib/lxc/var/lib/lxcsnapsがマウントされますね。

$ cat /proc/mounts | grep lxc
/dev/vdc1 /var/lib/lxc btrfs rw,relatime,space_cache 0 0
/dev/vdc1 /var/lib/lxcsnaps btrfs rw,relatime,space_cache 0 0

LXC 1.1系列の場合

上記で説明したLXC 1.0系列の仕様は少し不便ですね。そこでLXC 1.1系列ではlxc-snapshotを使った場合のスナップショットの保存場所が、コンテナ用のディレクトリ以下に変更されました。

たとえば、コンテナの保存場所が/var/lib/lxcで、スナップショット対象のコンテナがct01の場合は/var/lib/lxc/ct01/snaps以下にスナップショットが保存されるようになりました。

この仕様だと、特にサブボリュームをマウントする必要はなく、/var/lib/lxcがBtrfsであるだけで良いですね。

ただし、1.0からの移行の場合が考慮されていますので、/var/lib/lxcsnapsが存在する場合は、このディレクトリが引き続き使われます。

Btrfsを使ったコンテナの作成

準備ができたところでコンテナを作ってみましょう。作成はこの連載のこれまでに何度も出てきた操作と同じでlxc-createコマンドを使い、ストレージバックエンドを指定する-Bオプションにbtrfsを指定します。

$ sudo lxc-create -t download -n btrfs01 -B btrfs -- -d ubuntu -r trusty -a amd64

このように作成すると、コンテナのrootfsがBtrfsのサブボリュームとなります

$ sudo btrfs sub list /var/lib/lxc | grep btrfs01
ID 264 gen 57 top level 259 path btrfs01/rootfs

サブボリュームにコンテナイメージが保存されますので、コンテナのクローンやスナップショットの際にBtrfsの機能を便利に使えます。

このため、Btrfsをストレージバックエンドに使うと、rsyncによるコピーを行うディレクトリバックエンドのクローンやスナップショットに比べて、処理がかなり速く済み、ディスク容量も消費しません。コンテナの削除はサブボリュームを削除するだけなので一瞬です。

コンテナの設定に特にBtrfsであることがわかる記述はありません。これは少し不便かも知れませんね。

$ sudo grep -v '^#' /var/lib/lxc/btrfs01/config 

lxc.include = /usr/share/lxc/config/ubuntu.common.conf
lxc.arch = x86_64

lxc.rootfs = /var/lib/lxc/btrfs01/rootfs
lxc.utsname = btrfs01

lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.hwaddr = 00:16:3e:e2:fc:35

コンテナを保存する場所がBtrfsであっても、lxc-createコマンドで-B btrfsを指定しないと普通のディレクトリバックエンドとなってしまいますので注意が必要です。

$ sudo lxc-create -t download -n ct01 -- -d ubuntu -r trusty -a amd64
(-B btrfsなしでコンテナを作成)
$ sudo btrfs sub list /var/lib/lxc (ct01のrootfsはサブボリュームになっていない)
ID 259 gen 69 top level 5 path lxc
ID 260 gen 69 top level 5 path lxcsnaps
ID 264 gen 66 top level 259 path btrfs01/rootfs

前回の表1で紹介した"best"を-Bオプションに与えるとBtrfs,ZFS,LVM,ディレクトリの順に試してくれますので、常に-B bestlxc-createを実行すると良いかも知れませんね。

$ sudo lxc-create -t download -n ct01 -B best -- -d ubuntu -r trusty -a amd64
(-B bestを指定してコンテナを作成)
$ sudo btrfs sub list /var/lib/lxc | grep ct01
ID 266 gen 74 top level 259 path ct01/rootfs (←rootfsがサブボリュームになっている)

以上のように自動的に適切なストレージバックエンドを使ってコンテナを作成してくれます。

Btrfsを使ったコンテナのクローン

Btrfsをストレージバックエンドに使っているコンテナを-sオプションを付けてクローンをすると、Btrfsのスナップショット機能を使ってクローンを行います。

$ sudo time -p lxc-clone -o btrfs01 -n btrfs02 -s -B btrfs
Created container btrfs02 as snapshot of btrfs01
real 0.14
user 0.00
sys 0.00
$ sudo btrfs sub list /var/lib/lxc | grep btrfs0
ID 264 gen 99 parent 259 top level 259 path btrfs01/rootfs
ID 280 gen 100 parent 259 top level 259 path btrfs02/rootfs

この実行例では-sでスナップショットによるクローンを取得する指定をして、さらに-B btrfsとしてクローンをBtrfsを使ったコンテナにするように指定しています。どちらか片方だけの指定でもスナップショットによるクローンになります。しかし、わかりづらいので両方指定するようにした方が良いでしょう。

ここで-s-B btrfsの両方とも指定せずにクローンを作成すると通常のrsyncによるコピーのクローンを作成しますので注意しましょう。ただし、この場合でもクローン先のrootfsはBtrfsのサブボリュームとなります。

$ sudo time -p lxc-clone -o btrfs01 -n btrfs03 (-sも-B btrfsも付けずにクローン作成)
Created container btrfs03 as copy of btrfs01
real 4.94 (←時間がかかっている)
user 2.04
sys 1.86
$ sudo btrfs sub list -p /var/lib/lxc | grep btrfs0
ID 264 gen 99 parent 259 top level 259 path btrfs01/rootfs
ID 280 gen 100 parent 259 top level 259 path btrfs02/rootfs
ID 281 gen 101 parent 259 top level 259 path btrfs03/rootfs (←サブボリュームが作成されている)

以上のように-s -B btrfsオプションを付けた場合に比べてクローンに時間がかかっています。クローンで作成されたコンテナのrootfsはサブボリュームになっていることもわかります。

Btrfsのスナップショットを使った場合、クローンの元となるコンテナの更新や削除を行っても、クローン先のコンテナに影響を与えることはありません。クローン後はクローン元のコンテナとクローン先のコンテナは別々に更新できます。それぞれのコンテナを別々に更新した場合でもBtrfsの機能でクローン前と変化のないファイルについては内部的には同じファイルを指していますからディスクの容量の節約にもなりますね。

$ sudo ls /var/lib/lxc/btrfs01
config  rootfs
$ sudo ls /var/lib/lxc/btrfs02
config  rootfs

overlayfsやaufsの時のようなクローン元のコンテナを削除できないといったような制限はありませんので、以上のようにoverlayfsやaufsの時のようにコンテナディレクトリにフラグとなるようなファイルが作られることはありません。

$ sudo lxc-destroy -n btrfs01 (クローン元のコンテナを削除できる)
$ sudo lxc-start -n btrfs02 -d
$ sudo lxc-ls -f (クローン先のコンテナには影響ない)
NAME        STATE    IPV4        IPV6  AUTOSTART  
------------------------------------------------
btrfs02     RUNNING  10.0.3.112  -     NO         

このようにクローン元のコンテナを削除してもクローン先のコンテナは何事もなく動作しています。

Btrfsを使ったコンテナに対するlxc-snapshotコマンドの実行

lxc-snapshotコマンドについては第9回で簡単に説明をしました。この時は、ストレージバックエンドがディレクトリであるコンテナでの実行例を紹介しました。

lxc-snapshotコマンドは、コンテナのある時点のコンテナイメージを保存します。あとでコンテナイメージをスナップショット時点のイメージに戻したり、スナップショットから新しいコンテナを作成を作成したりできます。

内部的にはlxc-cloneと同じ処理を行います。lxc-cloneが既存コンテナを元に新しいコンテナを作成することを目的に使うのに対し、lxc-snapshotはある時点のコンテナイメージを保存することが目的となります。

lxc-snapshotコマンドの実行例を紹介する前に、第9回でも紹介したlxc-snapshotのオプションを見ておきましょう。

表1 lxc-snapshotのオプション
オプション オプションの意味
-c / --comment スナップショットにコメントを付けます。
-d / --destroy 指定した名前のスナップショットを削除します。
-L / --list スナップショットをリスト表示します。
-C / --showcomments リスト表示の際にコメントを表示します。
-r / --restore 指定したスナップショットを使ってリストアを行います。

それではストレージバックエンドがBtrfsであるコンテナを作成し、lxc-snapshotコマンドを実行してみましょう。

$ sudo lxc-create -t download -n btrfs01 -B btrfs -- -d ubuntu -r trusty -a amd64
(-B btrfsを指定してコンテナを作成)
$ sudo time -p lxc-snapshot -n btrfs01 (スナップショットの取得)
real 0.14
user 0.00
sys 0.00

以上のように一瞬でlxc-snapshotの処理は終了しています。スナップショットの確認をしてみましょう。

$ sudo lxc-snapshot -n btrfs01 -L (スナップショット一覧の表示)
snap0 (/var/lib/lxcsnaps/btrfs01) 2015:02:13 16:31:21
$ sudo btrfs sub list /var/lib/lxc | grep btrfs01 (サブボリュームの確認)
ID 264 gen 127 top level 259 path btrfs01/rootfs
ID 266 gen 127 top level 5 path lxcsnaps/btrfs01/snap0/rootfs

以上のように、-Lオプションを使ってスナップショットを確認するとsnap0という名前でスナップショットが作成されています。サブボリュームを確認してみると、snap0のrootfsがサブボリュームとなっていることがわかります。

このようにlxc-snapshotを使う場合は特にストレージバックエンドの形式を指定しなくても自動的にストレージバックエンドの形式を認識してスナップショットを取得します。

第9回 で紹介したように-rオプションを使えば、取得したスナップショットの状態にリストアできます。

$ sudo time -p lxc-snapshot -n btrfs01 -r snap0
real 0.16
user 0.00
sys 0.00

この例ではスナップショット元であるコンテナのrootfsをスナップショットの内容に戻しています。内部的にはbtrfs01コンテナのrootfsのサブボリュームを削除して、スナップショットとして取得したコンテナであるsnap0のrootfsのスナップショットをbtrfs01コンテナのrootfsの場所に作成しているようです。

LXC 1.1系列ではlxc-snapshotでスナップショットを取得すると、先に紹介したようにコンテナディレクトリ以下にスナップショットが保存されます。

$ sudo lxc-snapshot -n btrfs01 (スナップショットの取得)
$ sudo lxc-snapshot -n btrfs01 -L (スナップショット一覧の表示)
snap0 (/var/lib/lxc/btrfs01/snaps) 2015:02:13 17:11:09
$ sudo ls -F /var/lib/lxc/btrfs01/snaps/snap0 (snap0ディレクトリ以下の確認)
config  rootfs/  ts
$ sudo btrfs sub list /var/lib/lxc (サブボリュームの確認)
ID 257 gen 7 top level 5 path btrfs01/rootfs
ID 258 gen 8 top level 5 path btrfs01/snaps/snap0/rootfs

上記のようにスナップショットを取得した後、-Lオプションで確認してみると、/var/lib/lxc/btrfs01/snaps以下にsnap0が作られ、その下にファイルやディレクトリができています。

まとめ

今回はコンテナのストレージバックエンドとしてBtrfsを使った場合のコンテナの作成、クローン、スナップショットを紹介しました。

LXCのBtrfsバックエンドの機能は、今回紹介したようにサブボリュームとスナップショットを使うだけのシンプルなものです。それでもLXCの操作とBtrfsの操作を別々に行うよりは、コンテナのいろいろな処理が便利に行えることがおわかりいただけたのではないでしょうか。

次回も引き続きストレージバックエンドを便利に使う方法を紹介する予定です。

おすすめ記事

記事・ニュース一覧