非overlay なコンテナ
普段Linux の仮想化を行うときに動作の軽さの観点からLXC をよく使うのですが、コンテナを複製するときに普通にlxc-copy(旧lxc-clone) を使用した場合、数百MB あるファイルがそのまま複製されてしまい、ディスク領域を効率的に利用することができません。
今回はそれを解消するため、コンテナを複製するときにoverlay を使用して効率よくファイルを管理するように対応をしてみました。
overlay とは
overlay を使用して、コンテナのrootfs ファイルを読み取り専用の領域と読み書き可能な領域を分け、その両方のファイルをマージしたものを新コンテナとして使用することができるようになります。
複製した新しいコンテナで発生したファイルの変更は読み取り変更領域からコピーされ、読み書き可能領域で管理されるようになるため、必要最低限の差分ファイルのみ変更管理をすれば良くなるため、ディスクの領域を効率 良く使用することができます。
今回はoverlay を方式のLXC コンテナの作成についてをメインに説明していきますので、overlay の詳しい説明については他の参考資料を提示することにして、ここでは割愛させていただきます。
- OverlayFSについて
- 実践! OverlayFS
環境
今回LXC のoverlay を試した環境は次の通りです。
- 記号表示サンプル(一例)
Linux ディストリビューション | Fedora24 |
---|---|
カーネルバージョン | 4.6.3-300.fc24.x86_64 |
パッケージ | libvirt-daemon-driver-lxc-1.3.3.1-4.fc24.x86_64, lxc-templates-2.0.3-1.fc24.x86_64, lxc-libs-2.0.3-1.fc24.x86_64, lxc-2.0.3-1.fc24.x86_64 |
LXC のインストール手順については割愛します。
今回はすでにLXC がインストールされている前提で説明を進めていきます。
今回の手順を行った時に直面した問題について
今回Fedora template なLXC をoverlay で複製する手順について検証していったのですが、その際にいくつかの問題に直面しました。
このいくつかの問題に対して、あらかじめ対策をしておきます。
この対策方法は今後改善される可能性があるので、そうなった場合は本手順は無視して下さい。
コンテナ上で一部のパッケージ(例えばhttpd)をインストールするときに出るエラーの対応
Fedora テンプレートのコンテナ上で一部のパッケージ(今回の場合はhttpd)をインストールしようとすると、以下のようなエラーが出力されます。
Error unpacking rpm package httpd-2.4.23-3.fc24.x86_64
Error unpacking rpm package httpd-2.4.23-3.fc24.x86_64
error: unpacking of archive failed on file /usr/sbin/suexec;57870c2e: cpio: cap_set_file
httpd-2.4.23-3.fc24.x86_64 was supposed to be installed but is not!
このエラーが出てしまった場合は、ホストOS 側のテンプレート設定ファイルの中にあるsetfcap
の文字を取り除いてください。
......
##lxc.cap.drop = setfcap sys_nice sys_pacct sys_rawio
lxc.cap.drop = sys_nice sys_pacct sys_rawio
取り除いたらコンテナを一度シャットダウンし、そのあとに起動してください。
fedora00~# shutdown -h now
# lxc-start -n fedora00
# lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6
fedora00 RUNNING 0 - 192.168.122.246 -
fedora_base STOPPED 0 - - -
# ssh root@192.168.122.246
// 作業時点では、コンテナ上で"shutdown -r now" では反映されませんでした...
overlay 形式でlxc-copy するときに出るエラー
契機は不明だが、lxc-copy
コマンドを実行すると以下のようなメッセージが含まれるoverlayfs
デバイスが見つからないといったエラーが出ることがある。
...No such device - overlayfs:
普段は出ないので、再現したときにもう少し調査をしてみようと思います。
事象は、以下リンクのものと同様と思われます。
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=797694
fedora コンテナを作成する
それでは実際にoverlay を使ってコンテナを作成していきましょう。
まずは、コンテナのcopy 元となるコンテナをfedora_base
という名前で作成します。
# lxc-create --name fedora_base --template fedora
or
# lxc-create --name fedora_base --template fedora --backingstore=dir
lxc-create コマンドは--backingstore
オプションを何も指定しない場合はバッキングストアはdir 形式となり、rootfs ファイルのすべてのコピーが/var/lib/lxc/fedora_base
ディレクトリに作成されるようになります(非overlay な状態)。
複製元となるコンテナはこのdir 形式でバッキンぐストアを作成する必要があります。
コンテナを作成したら、コンテナのroot パスワードを設定します。
# chroot /var/lib/lxc/fedora_base/rootfs passwd
以上でcopy 元コンテナの作成は完了です。
コンテナをoverlay で複製する
lxc-copy
コマンドを使用して、バックエンドをoverlay 形式で作成します。
コマンドの指定はlxc-copy
コマンドに--backingstorage overlayfs
と--snapshot
を追加します。
# lxc-copy --name fedora_base --newname fedora00 --backingstorage overlayfs --snapshot
ここで、一旦overlayfs で作成したコンテナのrootfs を確認してみましょう。
# find /var/lib/lxc/fedora00/ -type f
/var/lib/lxc/fedora00/config
/var/lib/lxc/fedora00/delta0/etc/hostname
/var/lib/lxc/fedora00/lxc_rdepends
# ls -l /var/lib/lxc/fedora00/rootfs/
total 0
複製した直後の新コンテナは上記のファイルしかありません。
しかも、コンテナのディレクトリ配下のrootfs
配下はファイルがありません。
これはコンテナの複製がoverlay 形式で行われることによって、複製元となるコンテナ(fedora_base)のrootfs
ディレクトリをlower
、複製したのコンテナ(fedora00) のdelta0
ディレクトリをupper
としてoverlay マウントしている状態になります。
そうなることにより、以降、fedora00 上に新しいファイルが作成された場合には、fedora00 のdelta0 ディレクトリにファイルが新規に作成され、fedora_base から存在するファイルに対して変更が発生した場合はfedora_base のrootfs ディレクトリからfedora00 のdelta0 ディレクトリにファイルがコピーされ、fedora00 のdelta0 上のファイルに対して変更が加えられ、fedora00 コンテナ上のファイル(merge 領域)として反映されます(copy on write)。
それでは、新しくoverlay で作成したコンテナを起動させてみましょう。
# lxc-start -n fedora00
......
# lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6
fedora00 RUNNING 0 - 192.168.122.116 -
fedora_base STOPPED 0 - - -
コンテナを確認すると、192.168.122.116 のIP アドレスが今回は割り与えられました。
ssh でゲストOS へログインして、httpd をインストールしてみます。
# ssh root@192.168.122.116
fedora00~# dnf install -y httpd
...
# exit
httpd のインストールが完了したらLXC ホストOS 側でもう一度、fedora00 のファイル状況を確認してみましょう。
[root@myserver ~]# find /var/lib/lxc/fedora00/delta0 -type f
......
/var/lib/lxc/fedora00/delta0/etc/httpd/conf.d/README
/var/lib/lxc/fedora00/delta0/etc/httpd/conf.d/autoindex.conf
/var/lib/lxc/fedora00/delta0/etc/httpd/conf.d/userdir.conf
/var/lib/lxc/fedora00/delta0/etc/httpd/conf.d/welcome.conf
/var/lib/lxc/fedora00/delta0/etc/httpd/conf/httpd.conf
......
すると、overlay のupper 領域であるfedora00 のdelta0 にhttpd のファイルが作成されたことが確認できます。
これは以下の図のように更新対象のファイルがlowerdir
からupperdir
にコピーされ、upperdir
上でファイルが更新(もしくは新規作成)されるといったコピーオンライトが行われていることになります。
複製先のfedora00 コンテナが起動している状態で、複製元のfedora_base コンテナを起動して変更するとどうなる?
複製元のfedora_base コンテナのファイルを変更すると複製先のfedora00 コンテナのコピーオンライトされていないファイルは変更されてしまうのか実験してみました。
fedora00 が既に起動している状態で複製元のfedora_base
を起動します。
# lxc-start -n fedora_base
# lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6
fedora00 RUNNING 0 - 192.168.122.116 -
fedora_base RUNNING 0 - 192.168.122.50 -
複製元のコンテナにログインし、ファイルを作成してみます。
# ssh root@192.168.122.50
fedora_base~# echo "bar" > /root/foo.txt
fedora_base~# cat /root/foo.txt
bar
fedora_base~# exit
次に複製先のコンテナへログインし、先ほど作成したファイルと同じものが存在するか確認してみます。
# ssh root@192.168.122.116
fedora00~# cat /root/foo.txt
bar
複製先のコンテナにもファイルができちゃっていました(overlay であるということを考えれば、ある意味当然ですが…)。
現状、コンテナをoverlay で複製した場合、複製元のコンテナは変わらず更新可能な状態となっている(lxc で読み取り専用にしてくれない)ため、overlay で複製した場合は意識して複製元を更新しないようにしておく必要が あります。
同じ複製元から追加でコンテナを複製する
1 つの元コンテナから複数のoverlay を使ったコンテナを作ることも、問題なくできます。
fedora_base
コンテナからfedora00
コンテナを作成しましたが、同じ複製元コンテナfedora_base
から2 つ目のコンテナfedora01
を作成するコマンドは次の通りです。
# lxc-copy --name fedora_base --newname fedora01 --backingstore overlayfs --snapshot
このコンテナでは、overlay の構成としては、lowerdir=/var/lib/lxc/fedora_base/rootfs
, upperdir=/var/lib/lxc/fedora01/delta0
となります。
当然fedora01
は通常のコンテナとして使用することができますし、既存のfedora00
に変更影響を及ぼすこともありません。
overlay なコンテナからoverlay なコンテナを複製する
overlay なコンテナからoverlay なコンテナを複製することができます。
例えば、以下はfedora_base
からoverlay で複製したfedora00
コンテナから、overlay でfedora00_00
を複製するには以下の通りです。
# lxc-copy --name fedora00 --newname fedora00_00 --backingstore overlayfs --snapshot
ここで、一点注意していただきたいのは、/var/lib/lxc 配下のファイルを確認するとわかるのですが、新しく作成されたコンテナfedora00_00
のoverlay ディレクトリ構成はlowerdir=/var/lib/lxc/fedora_base
, upperdir=/var/lib/lxc/fedora00_00/delta0
となる点です。
これだとfedora00
のデータがfedora00_00
に引き継がれていないように見えますが、lxc-copy
コマンド実行時に/var/lib/lxc/fedora00/delta0
ディレクトリにあるファイルは/var/lib/lxc/fedora00_00/delta0
ディレクトリにコピーされるため、結果としてデータが引き継がれていることになります。
よって上記overlay ディレクトリ構成になっていることからもわかるようにfedora00
コンテナとfedora00_00
コンテナとの間にはoverlay 関係は無いため、fedora00
コンテナで発生した変更はfedora00_00
コンテナ には影響し無いことになります。
複製元 コンテナから引き継がれたファイルを複製先コンテナで削除した場合のoverlay の挙動
複製元コンテナfedora_base
上にあるファイルを複製先コンテナで削除した場合、overlay はどのような振る舞いをするか、見てみましょう。
今回はfedora_base
コンテナにある/root/foo.txt
をfedora00
上で削除してみます。
# lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6
fedora00 RUNNING 0 - 192.168.122.50 -
fedora_base STOPPED 0 - - -
# ssh root@192.168.122.50
fedora00 ~# rm -f /root/foo.txt
fedora00 ~# exit
# ls -la /var/lib/lxc/fedora00/delta0/root/
total 4
dr-xr-x--- 2 root root 42 Jul 19 11:53 .
drwxr-xr-x 6 root root 51 Jul 15 18:03 ..
-rw------- 1 root root 186 Jul 19 11:53 .bash_history
c--------- 1 root root 0, 0 Jul 19 11:53 foo.txt
すると、上記のようにmajour no 0、minor no 0 なキャラクタデバイスができていることが確認できます。
このようにしてupperdir
にキャラクタデバイスを作成することで、lowerdir
にあるファイルをマスクすることで、複製されたコンテナ上では削除されたファイルとしてコンテナ上では表示されないようになります。
overlay コンテナの削除
overlay なコンテナの削除は通常のコンテナの削除と同じ手順でできます。
# lxc-destroy -n fedora00
最後に
以上、overlay を使用したLXC コンテナの複製はいかがでしたでしょうか。
普段LXC コンテナを複製するときはoverlay を意識して使用することで、ディスク使用量を大幅に抑えることができます。
またコンテナ複製時にコピーするファイル数が通常のコンテナ複製よりも圧倒的に少ないため、例えば大量なAnsible 検証用コンテナを短時間で準備することができたりして、生産性向上に大きく貢献することができるでしょ う。
参考
-
LXC でoverlayfs を使用する
-
[Linux][Kernel][lxc] overlayfs と LXC 非特権コンテナの snapshot によるクローンAdd Starmomo-samurai
-
削除されたファイルは、マイナーNo0, メジャーNo0 なキャラクタデバイスでマスクされる