読者です 読者をやめる 読者になる 読者になる

TenForward

技術ブログ。はてなダイアリーから移転しました

overlayfs と LXC 非特権コンテナの snapshot によるクローン

Linux Kernel lxc

kernel に入るぞ、と言われつつ入ってない overlayfs。いつですかね?

なかなか凝ったことを試す時間が取れない今日このごろ、非常に薄い内容のエントリです。

(2014-05-15 追記) LXC では、ファイルシステムの機能を利用した snapshot による clone をサポートしています。しかし、非特権コンテナで clone を作成する場合、どうしても通常の rsync による clone になってしまいます。しかし、Ubuntuカーネルだと overlayfs が利用可能で、非特権コンテナの場合でも使用可能です。一般ユーザが overlayfs の操作が可能ということでなく、User Namespace 内の root の権限で overlayfs のマウントが可能になっているためです。(追記終わり)

(2014-10-08 追記)
今はオプションで "workdir" を指定する必要があるようです (いつから?)。以下は 3.17 (+patch) で確認。→ overlayfs.v22 (= 3.15) 以降のようですね。つまり現在の lxc-clone は 3.14kernel+v21 パッチまでの上でしか動きません。

# mkdir 1 2 3 4
# touch 1/lower
# touch 2/upper
# mount -t overlayfs -o lowerdir=1,upperdir=2,workdir=3 overlayfs 4
# touch 3/overlay
# umount 4
# find .
.
./1
./1/lower
./2
./2/upper
./2/overlay
./3
./3/work
./4

overlayfs

overlayfs を使ってみました。ドキュメント全く読んでないので (ヲイ) わかりませんが、カーネルが対応すれば特に何もすることはなさそうです。以下で試しました。

  • overlayfs パッチを当てた kernel 3.14.4 を入れた Plamo 5.2 環境。
  • Ubuntu 14.04LTS (パッチ不要)

パッチはこの辺りをご参照。

早速試してみます。

  1. 重ねあわせをするディレクトリを作り、確認用にファイルを作っておきます。
    # mkdir 1 2 3
    # touch 1/LOW
    # touch 2/HIGH
  2. マウントします。マウントされています。
    # mount -t overlayfs -o lowerdir=1,upperdir=2 overlayfs 3
    # mount -l | grep overlayfs
    overlayfs on /root/3 type overlayfs (rw,lowerdir=1,upperdir=2)
  3. ファイルを作ってみます。元々あったファイルに加えて、新しく作ったファイルも見えます。
    # cd 3
    touch OVERLAY
    # ls
    HIGH LOW OVERLAY
  4. umount します。
    # umount 3
  5. ディレクトリを確認してみます。
    # ls 1
    LOW
    # ls 2
    HIGH OVERLAY
    # ls 3

upperdir で指定したディレクトリが更新されていくわけですね。lowerdir で指定したディレクトリが更新されると、マウントされた overlayfs のディレクトリも更新されたようにみえます。

# cd 3
# ls
HIGH  LOW  OVERLAY
# cd ../1
# ls
LOW
# touch LOW2
# ls 
LOW  LOW2
# cd ../3
# ls
HIGH  LOW  LOW2  OVERLAY

これだけ。

Ubuntu 14.04 の非特権コンテナの overlayfs による clone

以下は一般ユーザで実行しています。非特権コンテナの作り方は Ubuntu 14.04 LTS での非特権コンテナ - TenForwardの日記 辺りをどうぞ。

"ct01" というコンテナを "ct02" という名前のコンテナに overlayfs を使って snapshot clone してみましょう。ちなみに aufs だとこんな風に怒られます。

$ lxc-clone -o ct01 -n ct02 -s -B aufs
lxc_container: Unsupported snapshot type for unprivileged users
lxc_container: Error copying storage
clone failed

overlayfs だとこんな風にあっさり成功。

$ lxc-ls
ct01  
$ lxc-clone -o ct01 -n ct02 -s -B overlayfs
Created container ct02 as snapshot of ct01
$ lxc-ls
ct01  ct02

ct02 のディレクトリを覗いてみると

$ cd .local/share/lxc/ct02
$ ls -F
config  delta0/  lxc_rdepends  rootfs/
$ grep lxc.rootfs config
lxc.rootfs = overlayfs:/home/karma/.local/share/lxc/ct01/rootfs:/home/karma/.local/share/lxc/ct02/delta0

つまり

  • ct01 の rootfs を lowerdir に
  • ct02 の delta0 ディレクトリを upperdir に

して、ct02 の rootfs ディレクトリに overlayfs でマウントするというわけですね。

$ lxc-start -n ct02 -d
$ lxc-ls --fancy
NAME  STATE    IPV4        IPV6  AUTOSTART  
------------------------------------------
ct01  STOPPED  -           -     NO         
ct02  RUNNING  10.0.3.178  -     NO         

ct02 に ubuntu ユーザでログインして $HOME/TEST ファイルを作ると、

$ cd ~/.local/share/lxc/ct02/delta0/home/ubuntu
$ ls
TEST

と delta0 ディレクトリにファイルが作られていきます。

一つ注意が必要なのは ct01 のファイルが更新されると ct02 のファイルも更新されてしまうので、なんか良くわからない状態になってしまいがちですね。普通に filesystem レベルでサポートされている snapshot を使った clone とはちょっと違うので、使い方も変えていく必要はあります。そういう場合は 1.0 ではサポートされない気がしますが、btrfs を使えばいけるようになりそうです→btrfs: support unprivileged create and clone · lxc/lxc@2659c7c · GitHub

Plamo 5.2 の非特権コンテナの clone

私にとってはここからが本題。

同じように Plamo でも出来るはず、ってことで試してみましたが...

$ lxc-clone -o ct01 -n ct02 -s -B overlayfs
lxc_container: Operation not permitted - overlayfs: error mounting /home/karma/.local/share/lxc/ct01/rootfs onto /usr/lib64/lxc options upperdir=/home/karma/.local/share/lxc/ct02/delta0,lowerdir=/home/karma/.local/share/lxc/ct01/rootfs
clone failed

(;_;) Why?? 偉い人教えて。(続く)

(2014-05-15 追記)
わかりました。overlayfs のパッチで User Namespace 内の root が overlayfs をマウント出来るようなフラグを与えました(Ubuntuカーネルはこれが当たってるはず)。具体的には fs/overlayfs/super.c 内の ovl_fs_type に FS_USERNS_MOUNT ってのをフラグで追加しました。

static struct file_system_type ovl_fs_type = {
       .owner          = THIS_MODULE,
       .name           = "overlayfs",
       .mount          = ovl_mount,
       .kill_sb        = kill_anon_super,
       .fs_flags       = FS_USERNS_MOUNT,
};

FS_USERNS_MOUNT は include/linux/fs.h に定義されています。

$ grep FS_USERNS_MOUNT include/linux/fs.h
#define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */

これで Plamo でも

$ lxc-clone -o ct01 -n ct02 -s -B overlayfs
Created container ct02 as snapshot of ct01

$ for c in /sys/fs/cgroup/*; do echo $$ > $c/karma/tasks; done
$ lxc-start -n ct02 -d
$ lxc-ls --fancy
NAME STATE IPV4 IPV6 AUTOSTART
--------------------------------------------
ct01 STOPPED - - NO
ct02 RUNNING 10.0.100.253 - NO