前回はLXCでも利用できるファイルシステムであるoverlayfsを紹介しました。
Linuxではいろいろなファイルシステムが使えますので、
LXCでも前回紹介したoverlayfsを始めとするいくつかのストレージバックエンドをサポートしており、
具体的には以下の操作をする場合にストレージバックエンドを指定して操作できます。
- コンテナの作成 (
lxc-create
) - コンテナのクローン (
lxc-clone
)
lxc-snapshot
コマンドでコンテナのスナップショットを取る場合も、
いずれのコマンドも第8回と第9回で簡単に説明しました。今回以降の数回で、
今回の記事中では実際の操作はUbuntu 14.
ストレージバックエンドの種類
lxc-create
、lxc-clone
共にストレージバックエンドは-B
オプションで指定します。ここで指定できるストレージバックエンドには表1に挙げるような種類があります。
名称 | lxc-create での使用 |
lxc-clone での使用 |
説明 |
---|---|---|---|
aufs | × | ○ | |
best | ○ | × | btrfs,zfs,lvm,dirの順に試す |
btrfs | ○ | ○ | |
dir | ○ | ○ | ディレクトリ |
lvm | ○ | ○ | LVM |
loop | ○ | ○ | ループバックデバイス |
none | ○ | × | dirのエイリアス |
overlayfs | × | ○ | |
zfs | ○ | ○ |
lxc-create
、lxc-clone
のそれぞれで
コピーによるクローン
それではさっそくクローンを試してみましょう。まずはコンテナの作成からです。/var/
が普通にext4である環境でコンテナを作成しましょう。
$ sudo lxc-create -n ct01 -t download -B dir -- -d ubuntu -r trusty -a amd64
-B dir
は指定しなくても同じです。ここではわかりやすいように明示的に指定しています。
クローンを実行する前にlxc-clone
のオプションを確認しておきましょう。
lxc-clone
コマンドのオプションオプション | オプションの意味 |
---|---|
-s | クローンをスナップショットで取得。LVMとbtrfsとzfsの時に指定可能。aufsとoverlayfsの時に指定が必要 |
-p | オリジナルのコンテナの |
-P | クローン先のコンテナの |
-B | 元のコンテナと違うバックエンドストレージを使う場合にバックエンドストーレジ形式を指定 |
-o | クローン元のコンテナ名 |
-n | クローン先のコンテナ名 |
最低限必要なオプションはクローン元を指定する-o
とクローンで新たに作成するコンテナ名を指定する-n
です。
また、-s
でスナップショットによるクローンを指定しない場合は、
では、
$ sudo time -p lxc-clone -o ct01 -n clone01 Created container clone01 as copy of ct01 real 4.43 user 2.14 sys 1.71 $ sudo lxc-ls clone01 ct01
lxc-clone
の終了後にlxc-ls
を実行すると、clone01
コンテナが作成されているのがわかります。
クローン先のコンテナの設定ファイルはlxc-clone
コマンドが自動的に作成します。クローン元のコンテナの設定ファイルを一度内部的に展開した後に必要部分を書き換えて出力しますので、lxc.
を使って共通ファイルをincludeしている場合でも、lxc.
を使わずに作成されます。
たとえばクローン元のct01
は以下のように非常にシンプルな記述です。
$ sudo cat /var/lib/lxc/ct01/config | grep -v "^#" lxc.include = /usr/share/lxc/config/ubuntu.common.conf lxc.arch = x86_64 lxc.rootfs = /var/lib/lxc/ct01/rootfs lxc.utsname = ct01 lxc.network.type = veth lxc.network.flags = up lxc.network.link = lxcbr0
一方、clone01
は以下のように全ての設定が書かれており、
$ sudo cat /var/lib/lxc/clone01/config
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry = sysfs sys sysfs defaults 0 0
:(略)
lxc.utsname = clone01
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.hwaddr = 00:16:3e:11:b2:90
lxc.cap.drop = sys_module
lxc.cap.drop = mac_admin
lxc.cap.drop = mac_override
lxc.cap.drop = sys_time
lxc.rootfs = /var/lib/lxc/clone01/rootfs
lxc.pivotdir = lxc_putold
rsyncによるコピーが行われていますので、
$ sudo du -sh /var/lib/lxc/ct01/rootfs (クローン元の容量) 379M /var/lib/lxc/ct01/rootfs $ sudo du -sh /var/lib/lxc/clone01/rootfs (クローン先の容量) 383M /var/lib/lxc/clone01/rootfs
aufs、overlayfsを使ったクローン
この2つのUnion Filesystemは、
aufs、
クローン元のストレージバックエンドがdirの場合はaufsとoverlayfsが、
aufs、-s
オプションを指定する必要があります。
では、ct01
コンテナのクローンをoverlayfsでスナップショットとして作成してみましょう。
$ sudo time -p lxc-clone -o ct01 -n overlayfs01 -s -B overlayfs Created container overlayfs01 as snapshot of ct01 real 0.04 user 0.00 sys 0.00
time
の出力を見ると、
クローンで作成したコンテナ用のディレクトリを見てみましょう。
$ sudo ls -F /var/lib/lxc/overlayfs01/ config delta0/ lxc_rdepends olwork/ rootfs/
config
ファイルとrootfs
ディレクトリは通常のコンテナにも存在しますね。目的も同じです。この2つも含めてクローン先のコンテナ用ディレクトリの中身をまとめておきます。
config
- コンテナの設定ファイル
delta0
- overlayfsの上層側ディレクトリ
lxc_
rdepends - このコンテナがどのコンテナに依存しているかを記述したファイル。依存するコンテナの
「保存場所( /var/
)」lib/ lxc と 「コンテナ名( ct01
)」が書かれています olwork
- overlayfsの
workdir
オプションで指定するディレクトリ。ここで使っているUbuntu 14.04 LTSの古いバージョンのoverlayfsでは使いません rootfs
- コンテナイメージのルート("/")。通常のコンテナと違いコンテナが起動していない時は空で、
overlayfsで下層側と上層側のディレクトリを重ねあわせてここにマウントします
LXCはクローンで作成したコンテナがoverlayfsを使用していることを、lxc.
の設定で認識します。
$ sudo grep lxc.rootfs /var/lib/lxc/clone01/config (コピーによるクローンのlxc.rootfsの確認) lxc.rootfs = /var/lib/lxc/clone01/rootfs $ sudo grep lxc.rootfs /var/lib/lxc/overlayfs01/config (overlayfsによるクローンのlxc.rootfsの確認) lxc.rootfs = overlayfs:/var/lib/lxc/ct01/rootfs:/var/lib/lxc/overlayfs01/delta0
コピーによるクローンで作られたコンテナのlxc.
は、lxc-create
で作られたコンテナと同様にディレクトリを示しています。一方、lxc.
はコロンで区切られた設定となっています。
aufs、
lxc.rootfs = (aufsもしくはoverlayfs):(下層側ディレクトリ):(上層側ディレクトリ)
overlayfsの場合の実際の設定を見てみると、delta0
というディレクトリを指定しているのがわかります。つまりクローン元のコンテナイメージは読み込み専用の下層側として使うわけですね。
クローン直後のコンテナイメージの容量を確認してみましょう。
$ sudo du -sh /var/lib/lxc/overlayfs01/delta0 12K /var/lib/lxc/overlayfs01/delta0
まだコンテナの起動を行っていないので、delta0
ディレクトリの中を見てみると/etc/
のみ存在します。LXCはコンテナ内のホスト名を変更するために/etc/
の名前を変更します/etc/
ファイルが存在する場合のみです)。
$ sudo tree -A /var/lib/lxc/overlayfs01/delta0 /var/lib/lxc/overlayfs01/delta0 └── etc └── hostname 1 directory, 1 file $ sudo cat /var/lib/lxc/overlayfs01/delta0/etc/hostname overlayfs01
コンテナを起動すると、delta0
ディレクトリを重ねあわせて、rootfs
ディレクトリにマウントします。実際にコンテナを起動して、
$ sudo lxc-start -n overlayfs01 -d $ sudo lxc-attach -n overlayfs01 -- cat /proc/mounts | grep overlayfs /var/lib/lxc/ct01/rootfs / overlayfs rw,relatime,lowerdir=/var/lib/lxc/ct01/rootfs,upperdir=/var/lib/lxc/overlayfs01/delta0 0 0
このマウントはコンテナのマウント名前空間内で行われますので、lxc-attach
でコンテナ内に入り込んでマウントの確認をしています。
試しにコンテナ内にファイルを作成してみましょう。
$ sudo lxc-attach -n overlayfs01 -- touch /root/testfile (コンテナにファイルを作成) $ sudo lxc-stop -n overlayfs01 $ sudo tree -A /var/lib/lxc/overlayfs01/delta0 (上層側ディレクトリ以下の確認) /var/lib/lxc/overlayfs01/delta0 :(略) ├── etc │ ├── hostname │ ├── mtab │ └── nologin -> (overlay-whiteout) ├── root │ └── testfile ├── run │ └── plymouth └── var :(略) └── log ├── boot.log ├── dmesg ├── dmesg.0 ├── kern.log ├── syslog :(略) 13 directories, 35 files $ sudo du -sh /var/lib/lxc/overlayfs01/delta0 172K /var/lib/lxc/overlayfs01/delta0
上記のようにroot/
が作成されていますし、
このようにoverlayfsを使うと素早く、
このような状態でクローン元のコンテナがなくなってしまってはクローンしたコンテナの起動に困りますね。そこでLXCのコマンドやライブラリを使っている限りはこのような問題は起きないような工夫がされています。
クローンを作成すると、
ubuntu@gihyo:~$ sudo ls -F /var/lib/lxc/ct01/ config lxc_snapshots rootfs/ ubuntu@gihyo:~$ sudo cat /var/lib/lxc/ct01/lxc_snapshots 1
上記のようにlxc_
というファイルが作成され、ct01
を削除しようとすると、
$ sudo lxc-destroy -n ct01 lxc_container: lxccontainer.c: lxcapi_destroy: 2063 container ct01 has dependent snapshots Destroying ct01 failed
もちろん、ct01
用のディレクトリやファイルはLXCのコマンドを使わないでrm
コマンドなどで消去できますので、
クローンで作成されたコンテナのクローン
overlayfsによるクローンで作成されたコンテナの更にクローンをoverlayfsで作成するとどうなるでしょうか。さっそくやってみましょう。
$ sudo time -p lxc-clone -o overlayfs01 -n overlayfs02 -s -B overlayfs Created container overlayfs02 as snapshot of overlayfs01 real 0.05 user 0.00 sys 0.00
overlayfs01
コンテナをクローンしたときと同様に一瞬でクローンが作成されました。できあがったコンテナを先ほどと同様に確認していきましょう。
まずはlxc.
がどのように設定されているのか確認です。
$ sudo grep lxc.rootfs /var/lib/lxc/overlayfs02/config lxc.rootfs = overlayfs:/var/lib/lxc/ct01/rootfs:/var/lib/lxc/overlayfs02/delta0
overlayfs01
コンテナでも下層側ディレクトリに指定されていたct01
のコンテナイメージがそのまま下層側に指定されています。上層側ディレクトリはoverlayfs02
コンテナ用のディレクトリですね。
それではクローン元のoverlayfs01
コンテナで行われた変更はどうやってクローン先のoverlayfs02
コンテナに反映されているのでしょうか? 実は、
つまりクローン時のクローン元のコンテナのファイルがコピーされるだけなので、overlayfs01
)overlayfs02
)
overlayfs01
コンテナとoverlayfs02
コンテナの上層側ディレクトリの使用量を比べてみましょう。
ubuntu@gihyo:~$ sudo du -sh /var/lib/lxc/overlayfs01/delta0 172K /var/lib/lxc/overlayfs01/delta0 ubuntu@gihyo:~$ sudo du -sh /var/lib/lxc/overlayfs02/delta0 172K /var/lib/lxc/overlayfs02/delta0
同じだけ使用していますね。使用量だけ見てもわかりませんので、delta0
ディレクトリのツリーを比較してみましょう。
$ diff <(sudo tree /var/lib/lxc/overlayfs01/delta0) <(sudo tree /var/lib/lxc/overlayfs02/delta0) 1c1 < /var/lib/lxc/overlayfs01/delta0 --- > /var/lib/lxc/overlayfs02/delta0
ちょっとわかりづらいコマンドの実行ですね。上記の例はそれぞれのコンテナのdelta0ディレクトリを引数に指定してtree
コマンドを実行した出力をdiff
で比較しています。tree
コマンドの1行目は引数で指定したディレクトリの部分だけが違っているのがわかります。
存在するファイルやディレクトリはクローン直後は同じであることがわかりますが、/etc/
の変更はされています。
$ sudo cat /var/lib/lxc/overlayfs02/delta0/etc/hostname overlayfs02
そして、ct01
にクローン時にできたlxc_
ファイルの中身は、
$ sudo cat /var/lib/lxc/ct01/lxc_snapshots 2
ちなみにこのlxc_
ファイルは、
aufsによるクローン
ここまでoverlayfsを使ったクローンを紹介してきました。aufsを使う場合も、
$ sudo time -p lxc-clone -o ct01 -n aufs01 -s -B aufs (aufsによるクローン) Created container aufs01 as snapshot of ct01 real 0.17 user 0.00 sys 0.00 $ sudo ls -F /var/lib/lxc/aufs01/ (クローン先コンテナ用ディレクトリ内の確認) config delta0/ lxc_rdepends rootfs/ $ sudo grep lxc.rootfs /var/lib/lxc/aufs01/config (lxc.rootfsの設定の確認) lxc.rootfs = aufs:/var/lib/lxc/ct01/rootfs:/var/lib/lxc/aufs01/delta0
overlayfsよりは少し時間がかかっているようですね。でも一瞬でクローンが終わるのには変わりません。コンテナ用ディレクトリの下にできるファイルやディレクトリは、lxc.
に設定される値も"overlayfs"となっていた部分が"aufs"になっているだけです。
$ sudo du -sh /var/lib/lxc/aufs01/delta0 (コンテナイメージの容量の確認) 20K /var/lib/lxc/aufs01/delta0 $ sudo tree -A /var/lib/lxc/aufs01/delta0 (コンテナのルート以下の確認) /var/lib/lxc/aufs01/delta0 └── etc └── hostname 1 directory, 1 file $ sudo cat /var/lib/lxc/aufs01/delta0/etc/hostname (ホスト名書き換えの確認) aufs01
overlayfsと同様に、delta0
以下には/etc/
が存在しているだけですので使用量はわずかです。
ではコンテナを起動してマウントされている様子を見てみましょう。
$ sudo lxc-start -n aufs01 -d
$ sudo lxc-attach -n aufs01 -- cat /proc/mounts | grep aufs
(コンテナ内でマウント情報を確認)
/var/lib/lxc/ct01/rootfs / aufs rw,relatime,si=8b3011feb4cad46c 0 0
マウントされていますね。この情報からはわかりませんが、delta0
ディレクトリを読み書き可能で、
$ sudo lxc-stop -n aufs01 $ sudo du -sh /var/lib/lxc/aufs01/delta0 176K /var/lib/lxc/aufs01/delta0
コンテナの起動によってログなどが増えたため、delta0
ディレクトリの容量が増えていることがわかります。
overlayfsと同様に、
$ sudo lxc-clone -o aufs01 -n aufs02 -s -B aufs (aufsコンテナをaufsクローン) Created container aufs02 as snapshot of aufs01 $ sudo grep lxc.rootfs /var/lib/lxc/aufs02/config (クローン先のlxc.rootfsの確認) lxc.rootfs = aufs:/var/lib/lxc/ct01/rootfs:/var/lib/lxc/aufs02/delta0
aufsで差分を保存するためのディレクトリの中身がrsyncによってコピーされ、
一般ユーザによるクローン
Ubuntu 14.
$ id -u 1000 $ lxc-clone -o ct01 -n overlay01 -s -B overlayfs Created container overlay01 as snapshot of ct01 $ lxc-start -n overlay01 -d $ lxc-attach -n overlay01 -- cat /proc/mounts | grep overlay /home/ubuntu/.local/share/lxc/ct01/rootfs / overlayfs rw,nodev,relatime,lowerdir=/home/ubuntu/.local/share/lxc/ct01/rootfs,upperdir=/home/ubuntu/.local/share/lxc/overlay01/delta0 0 0
vanilla kernelだと、
同様にユーザ名前空間内の特権ユーザではaufsをマウントできませんので、
- ※)
- 最近のaufsでは
allow_
というモジュールパラメータを有効にすると、userns ユーザ名前空間内の特権ユーザがaufsをマウントできるようになっているようです。そこで筆者が一般ユーザが起動したLXCコンテナでもaufsが使えるようなパッチを投稿し、 マージされました。ただし、 Ubuntuのカーネルに適用されているaufsのパッチは古いバージョンのようで、 最新のUbuntu環境でもこのモジュールパラメータは使えないようです。
overlayfs、aufsを使ったクローンの際の注意点
クローン元のコンテナ
先にも述べたようにoverlayfs、
しかし、
ベースとなる側、
overlayfsを使う際のファイルシステム
LXCではコンテナイメージの保存場所に使われているファイルシステムが何であるかに関わらず、
たとえば、
LXCでdirストレージバックエンドを使用している場合に、
LXCのoverlayfs対応
前回説明したように、
しかし執筆時点では、
なお、
まとめ
今回はoverlayfsとaufsを使ったコンテナのクローンを細かく見ました。
LXCでこれらのファイルシステムを使って、
次回以降も、
LXC 1.1.0
今回の原稿を書いている最中にLXCの初のメジャーバージョンアップである1.
LXC 1.
- CRIUを使ったコンテナのチェックポイント・
リストア - initとしてsystemdを使ったコンテナのサポート
の2点です。