AUFSのためにKernelをビルドしてAUFSを試した

LXCでAUFSを使うので、AUFSを使えるようにKernelをビルドした話。

使ったOSはCentOS 6.2(x86_64)。6.4で試せばよかった。

ソースコードを取得。

aufsのプロジェクトからgit cloneする。
aufsのプロジェクトにKernelのソースコードもある。
gitはyum install gitしておきましょう。

cd /usr/local/src
yum install -y git
git clone git://git.code.sf.net/p/aufs/aufs3-linux aufs-aufs3-linux
cd aufs-aufs3-linux/
git checkout refs/tags/v3.13

# 必要なさそうだけど必要だった
cd /usr/local/src/aufs-aufs3-linux
git clone git://git.code.sf.net/p/aufs/aufs3-standalone 
cd  aufs3-standalone
git checkout origin/aufs3.13

# util
cd /usr/local/src/aufs-aufs3-linux
git clone git://git.code.sf.net/p/aufs/aufs-util
cd  aufs-util
git checkout origin/aufs3.9
# aufs3.9を使うのは、aufs3.13のものが無かったので。多分大丈夫だと思う。

パッチ当て

本家Kernelを使っているときに必要な作業かもしれないので、本家からforkしたaufs-aufs3-linuxを使うなら要らないかもしれない。

cd /usr/local/src/aufs-aufs3-linux
patch -N -p1 < ./aufs3-standalone/aufs3-kbuild.patch
patch -N -p1 < ./aufs3-standalone/aufs3-base.patch
patch -N -p1 < ./aufs3-standalone/aufs3-mmap.patch
patch -N -p1 < ./aufs3-standalone/aufs3-standalone.patch

standaloneからいくつかファイルをコピーする。

# \マークは含めておかないとforceオプションが効かない。yes | cp -r でもいいけど。
\cp -rf ./aufs3-standalone/{Documentation,fs,include/uapi/linux/aufs_type.h} ./
\ cp ./aufs3-standalone/include/uapi/linux/aufs_type.h ./include/uapi/linux/aufs_type.h 

旧kernelのconfig複製

現在のKernelのconfigファイルをコピー。
なくても、yumでkernel-develを入れれば入るはず。

cd /usr/local/src/aufs-aufs3-linux
mv .config .config.org
cp /boot/config-`uname -r` ./.config

AUFS向け設定

AUFSのために以下のあたりを有効にする

cat << __EOF__ >> .config
CONFIG_AUFS_FS=m
CONFIG_AUFS_BRANCH_MAX_127=y
CONFIG_AUFS_SBILIST=y
CONFIG_AUFS_EXPORT=y
CONFIG_AUFS_INO_T_64=y
CONFIG_AUFS_BR_RAMFS=y
CONFIG_AUFS_BR_FUSE=y
CONFIG_AUFS_POLL=y
CONFIG_AUFS_BDEV_LOOP=y
__EOF__

上の設定はmenuconfigで以下の設定をしたのと同じ。(数が一致しないけど、依存関係で有効になったりするものもあるからそういうもの。)

File systems  --->
    -*- Miscellaneous filesystems  --->  
        <M>   Aufs (Advanced multi layered unification filesystem) support (NEW)
             [*]     NFS-exportable aufs
             [*]     Ramfs (initramfs/rootfs) as an aufs branch 
             [*]     Fuse fs as an aufs branch 

LXC向け設定

LXCを使うつもりなので、以下のページを参考にして設定をしておく。
http://lxc.teegra.net

cat << __EOF__ >> .config
CONFIG_GROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_CGROUP_SCHED=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_KMEM=y
CONFIG_MM_OWNER=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_SECURITY_FILE_CAPABILITIES=y
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
__EOF__


ただ、いくつか名前が変わってた。2009年の記事だし仕方ない。

  • CONFIG_CGROUP_MEM_RES_CTLR
    • CONFIG_MEMCGの事
  • CONFIG_CGROUP_MEM_RES_CTLR_SWAP
    • CONFIG_MEMCG_SWAPの事
  • CONFIG_CGROUP_NS
    • ない
  • CONFIG_SECURITY_FILE_CAPABILITIES
    • ない。調べたら削除するパッチが2009年ぐらいに出てて、マージされたんだと思う。

この辺りで調べました。http://cateee.net/lkddb/web-lkddb
どのバージョンのkernelに存在したかわかるので、そこから変更したんかなーとか推測できる。


そんなこんなで、2.6系のkernelと3.x系のkernelは大分差分があり、いくつか設定がなかったりしたので調整する。
(特にNetwork周りの設定の定義名がIPV4,IPV6で分けて書かれており、デフォルト無効になっているなど。)
古いconfigファイルから今風のconfigファイルに作り替える。

# 古いconfigファイルを新しいconfigファイルに作り直す
# 設定値は対話で入力すると日が暮れるので、デフォルト値を使うようにする。(そのためのolddefconfig)
make olddefconfig
# 少しグラフィカルな設定変更を行う
yum install ncurses-devel -y # 必要なモジュール
make menuconfig


以下は元のconfigとのdiff取ったりして、なるべく元のKernelの設定になるようにしてみたつもり。
相変わらず設定の意味はよくわかってない。なので自分専用って事で。

cat << __EOF__ >> .config
# ネットワーク周りだけならここらへん
CONFIG_NET_IPGRE_DEMUX=m
CONFIG_NF_NAT=m
CONFIG_NF_NAT_NEEDED=y
CONFIG_NF_NAT_PROTO_DCCP=m
CONFIG_NF_NAT_PROTO_UDPLITE=m
CONFIG_NF_NAT_PROTO_SCTP=m
CONFIG_NF_NAT_AMANDA=m
CONFIG_NF_NAT_FTP=m
CONFIG_NF_NAT_IRC=m
CONFIG_NF_NAT_SIP=m
CONFIG_NF_NAT_TFTP=m
CONFIG_NF_TABLES=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
CONFIG_NFT_RBTREE=m
CONFIG_NFT_HASH=m
CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_TARGET_NETMAP=m
CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
CONFIG_NF_TABLES_IPV4=m
CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
CONFIG_NF_NAT_IPV4=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_NF_NAT_PROTO_GRE=m
CONFIG_NF_NAT_PPTP=m
CONFIG_NF_NAT_H323=m
CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
CONFIG_NF_TABLES_BRIDGE=m
# その他よくわからんちん
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_EXPERT=y
CONFIG_UNINLINE_SPIN_UNLOCK=y
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT=y
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_XEN=y
CONFIG_XEN_DOM0=y
CONFIG_XEN_PRIVILEGED_GUEST=y
CONFIG_XEN_PVHVM=y
CONFIG_XEN_MAX_DOMAIN_MEMORY=500
CONFIG_XEN_SAVE_RESTORE=y
CONFIG_KVM_GUEST=y
CONFIG_PARAVIRT_CLOCK=y
CONFIG_PCI_XEN=y
CONFIG_XEN_PCIDEV_FRONTEND=y
CONFIG_OPENVSWITCH_GRE=y
CONFIG_SYS_HYPERVISOR=y
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_HYPERV_STORAGE=m
CONFIG_XEN_NETDEV_FRONTEND=y
CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y
CONFIG_HYPERV_KEYBOARD=m
CONFIG_HVC_IRQ=y
CONFIG_HVC_XEN=y
CONFIG_HVC_XEN_FRONTEND=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_IMAGEBLIT=y
CONFIG_FB_SYS_FOPS=y
CONFIG_FB_DEFERRED_IO=y
CONFIG_HYPERV=m
CONFIG_HYPERV_UTILS=m
CONFIG_HYPERV_BALLOON=m
CONFIG_XEN_FBDEV_FRONTEND=y
CONFIG_XEN_BALLOON=y
CONFIG_XEN_SCRUB_PAGES=y
CONFIG_XEN_DEV_EVTCHN=y
CONFIG_XEN_BACKEND=y
CONFIG_XENFS=y
CONFIG_XEN_COMPAT_XENFS=y
CONFIG_XEN_SYS_HYPERVISOR=y
CONFIG_XEN_XENBUS_FRONTEND=y
CONFIG_XEN_GNTDEV=m
CONFIG_XEN_GRANT_DEV_ALLOC=m
CONFIG_SWIOTLB_XEN=y
CONFIG_XEN_PCIDEV_BACKEND=m
CONFIG_XEN_PRIVCMD=y
CONFIG_XEN_ACPI_PROCESSOR=m
CONFIG_XEN_HAVE_PVMMU=y
CONFIG_NFS_FS=y
CONFIG_NFS_V2=y
CONFIG_NFS_V3=y
CONFIG_NFS_V4=y
CONFIG_NFS_V4_2=y
CONFIG_PNFS_FILE_LAYOUT=y
CONFIG_NFS_V4_SECURITY_LABEL=y
CONFIG_LOCKD=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
__EOF__

一応これでlxc-checkconfigが全部緑になったので良いはず。

Kernelのビルドとインストール

# 必要なライブラリ
yum install bc

# ビルド
make clean
make -j5 bzImage && make -j5 modules # -jの値は並列数になる。CPUの数+1ぐらいにしている。
# インストール
make modules_install && make install

# boot時に新しく作ったkernelを読ませるようにする(installすると0番目に入るので、0にする。)
sed -i.bak 's/default=1/default=0/' /boot/grub/grub.conf

# Reboooooooooooooooooot
reboot

AUFS-utilのビルドとインストール

# ヘッダを/usr/include/linuxへコピー(READMEには書いてあったけど読み間違いしてる気がするので、多分要らない)
# cd /usr/local/src/aufs-aufs3-linux
# cp -p ./aufs_type.h /usr/include/linux/

cd /usr/local/src/aufs-aufs3-linux/aufs-util
yum install glibc-static
make CPPFLAGS="-I /usr/local/src/aufs-aufs3-linux/usr/include -I /usr/local/src/aufs-aufs3-linux/aufs3-standalone/include"
make install

AUFSを使う

まず作業ディレクトリを用意する。普通のファイルシステムであればどこでも。

mkdir /tmp/aufs-example


ブランチ用のディレクトリを用意する
read-only はaufsから見て読み取り専用ディレクトリ。ベースになる部分となる。
work はaufsから見て作業用ディレクトリ。aufsによって編集されたファイルがここに置かれたり削除されたりする。
work はあくまでaufsの作業用ディレクトリで、ユーザがここを操作するといったことは無い。

cd  /tmp/aufs-example
mkdir read-only work


read-onlyにファイルをいくつか作る

cd /tmp/aufs-example/read-only
echo "read-only-1" > ./file1.txt
echo "read-only-2" > ./file2.txt
ls -l

実際にAUFSでマウントする
マウント先となるrootfsを作る。

cd /tmp/aufs-example
mkdir rootfs


マウントする。brオプションで用意したディレクトリを並べる。左にあるものが一番上にくるイメージ。

# SELinuxの都合上、contextオプションも指定する。
# 何も指定しないとtypeがunlabeled_tになってしまう。(これだと書き込めない)
# ただ設定しているtmp_tはたぶん適切ではない。が、まずは書き込みたいのでとりあえず適当に設定。
mount -t aufs -o context=unconfined_u:object_r:tmp_t:s0 -o br=/tmp/aufs-example/branched:/tmp/aufs-example/read-only=ro aufs /tmp/aufs-example/rootfs


手動でマウントするのではなく、勝手にマウントさせたいときは/etc/fstabに書いてmount -a。

echo 'aufs /tmp/aufs-example/rootfs aufs br=/tmp/aufs-example/work:/tmp/aufs-example/read-only=ro,context=unconfined_u:object_r:tmp_t:s0 0 0' >> /etc/fstab
mount -a


マウントした内容をみる。
workには何もしていないので、read-onlyと同じ内容が見える。

cd /tmp/aufs-example/rootfs
ls -l


マウント先にファイルを新規追加してみたり、file2.txtを削除してみる

cd /tmp/aufs-example/rootfs
echo "rootfs-3" > file3.txt
rm -f file2.txt


確認。
file3.txtが追加され、file2.txtが削除されている。ふつーにファイル操作できている。

ls -l 

rootfsの見え方としてはこんな感じ。


read-onlyの中身を確認してみる。
read-onlyは何も変わっていないで、file1.txtとfile2.txtが残ったまま。

cd /tmp/aufs-example/read-only
ls -l 


続いてworkの中身も確認。
こちらにはほぼrootfsにある同じ情報であるが、隠しファイルが存在する。
削除を判定するために".wh."プレフィクスをつけて管理している模様?
file3.txtは追加した内容そのものだった。

cd /tmp/aufs-example/work
ls -al


いたずらしてみる。削除情報らしきファイルを削除する

cd /tmp/aufs-example/work
rm -f .wh.file2.txt
ls -al


確認。file2.txtが出てくる。やっぱりな!

cd /tmp/aufs-example/rootfs
ls -l


ところで、rootfsにfile2.txtと.wh.file2.txtを作ったらどうなるんだろうなー、file2.txtが削除されたことになるんじゃないかなーと思いやってみようとしたら

cd /tmp/aufs-example/rootfs
echo "hogehoge" > .wh.file2.txt
# -bash: .wh.file2.txt: 許可されていない操作です

ダメでした。

乾燥

AUFS自体は簡単に扱えて良い。
これだけだとあんまりありがたみが実感ないけど、LXCで組み合わせて使うことを考えると、複数のファイルの複製が不要になるので、コンテナを作る時間も減るし、ファイルサイズも比較的小さく済むのが良い。
現状はlxc-createすると、400MB近いコピーが走るので、作って壊す・・・というにはちょっと重い。(十分早いけど)


あとSELinux辛い。
マウントしたらunlabeled_tになってファイル作れないってなんだよ!ほかの人はなんで同じ問題にひっかからないんだよ!!
SELinuxを無効にするのが当たり前なのか、本当は問題もないけど自分が間抜けな設定をして起きてるのか、よくわからん。
これを切り分けるにはどうアプローチしていけばいいんだろうなー。
動くからそれでいいやっていう考え方はしたくないし。・・・上の手順では結構やっちゃってるけど。

勉強しないとだめすなぁ。