環境構築を支えるUnionfsとcloop

以下のテキストは、執筆時当時の情報を元に書いたものであり、 現在の情勢にそぐわないことを含む場合があるので注意されたい。 また、テキストは最終提出原稿で校正を経る前のものなので、実際にOSM 本誌に記載されたものとは異なる。誤字脱字等そのままである。

致命的な誤り以外は加筆修正等は行なわないので情報の鮮度に気をつけつつ 利用して欲しい。

目次


「特殊ファイルシステムを使いこなせ!」

データを暗号化できるファイルシステム、ログ構造化などによるシステムクラッ
シュ耐性の強いファイルシステム、自由度の高い拡張アクセスコントロールを使
えるファイルシステム、などなど、色々なファイルシステムが開発されている。
そうした性能を追求するものもさることながら、使い勝手をよくしたり、環境構
築の補助となるファイルシステムがある。また、ユーザ自身でファイルシステム
を定義したり拡張したりする枠組みもあり、簡単なスクリプトが書ける程度の腕
さえあれば、自由な発想で面白いファイルシステムが作れる。

本特集では「自分環境改善計画」を目指して、趣向の変わったファイルシステム
の使いこなし方を探っていく。

======================================================================
Part1: 環境構築を支えるUnionfsとcloop
======================================================================


■
■Unionfsによるミニ環境構築の意義
■

Part* でとりあげるUnionfsは新しいものではないが、近年KNOPPIXやFreeSBIEな
どに代表される1CDシステムで利用されたことにより、その利便性が非管理者ユー
ザにも明らかになり広く注目されるようになった。Unionfsはシステム本体の環
境内にもうひとつの「ミニ環境」を作るときに威力を発揮する。まずは、どんな
局面で使えるのかについて触れよう。

●ネットワークサービスは牢獄環境で

ウィルス・ワームが蔓延する昨今、Unixとはいえ安心してはいられない。クラッ
カー達は日々セキュリティホールを探し、見付かるやいなや攻撃をしかけて来る。
Unix系OSで運営されているWebサーバが乗っ取られる事件もあちこちで起きている。
それらのほとんどは、ネットワークサービスデーモン経由でのアクセスでroot権
限を取られてしまうことに起因するのだが、そのデーモンプログラムがシステム
の限られたりソースにしかアクセスできないようにしておけば万が一のときの被
害も最小限に食い止めることができる。

デーモンプログラムに限られたリソースのみ与えるにはシステム全体から隔離し
た領域に閉じ込めればよい。一般的なものとしては、古来より使える「chroot
jail」がそれにあたる。chroot()はある特定のディレクトリをルートディレクト
リとしてするシステムコールで、chroot()すると以後それより上のディレクトリ
は全く見えなくなる。

このような牢獄環境の意義は別の機会に譲るとして、そのような環境を作る場合
のことを考えよう。仮にWebサーバをchroot環境で動かすとした場合、chrootする
ディレクトリが「第2のルートディレクトリ」となるわけであるから、各種プログ
ラムの起動に必要な最低限のディレクトリやファイルが揃っていなくてはならな
い。つまり、そうすると /bin /sbin /usr/bin /usr/bin など、OSの標準的シス
テムディレクトリが複数個存在することになり、システムのアップグレードをす
るときに保有している牢獄環境の数だけファイルの更新を行なわなければならな
い。また、牢獄環境が本体の環境と全く同じ「ファットな環境」であった場合、
侵入者によって万が一root権限を取られたときに、完全なシステムを乗っ取っら
れたのと大差ないことになってしまう。

このようなときに既存のシステムディレクトリをリードオンリで牢獄環境にマウ
ントできれば、改ざんも防げる上に管理上の手間も軽減できる。

既存のディレクトリを別のディレクトリにマウントすることのできるファイルシ
ステムとして、Union file system(Plan9, BSD, Linux), Loopback file
system(SunOS), Null file system(BSD) などがあり、これらを上手に利用する
ことで「サブセット環境」を効率よく作ることができる。

●パッケージの更新の実験

使用しているソフトウェアの新しいバージョンが出たので、パッケージシステム
でアップグレードしたら、それが依存するソフトウェアのバージョンも変わりな
んだか調子わるくなった。といった経験はないだろうか。大きめなパッケージの
更新は緊張がともなうし、後もどりも難しい。そんなときに、上述したchroot環
境に現在の環境を再現し、そこで実験的にアップグレード操作してみることで予
行演習ができる。そのときに、chroot環境にファイルをコピーするのではなく、
Unionfsマウントすることで、コピーもせず、本体ディレクトリも壊すことなく
実験が行なえる。

●CD1枚持ち歩き環境の構築

CDでOSを起動した場合、リードオンリメディアであるから通常は書き込みできな
い。しかし、書き込み可能メディアをUnionfsでCD状のディレクトリと重ね合わせ
て使うことで修正したファイルの記録を次回以降も利用できる。このような環境
は既にFreeSBIEやKNOPPIXで気軽に体験できるようになっているが、今回は
Unionfsの使い方の練習という意味で「自分環境」を1CDシステムとして作成する
方法を紹介する。

■
■Unionfsのはたらき
■

Unionfsは複数のディレクトリをまとめて、各ディレクトリ全ての和集合を合成す
るファイルシステムである。和集合ディレクトリの作り方は Unionfs の実装によっ
て微妙に異なるので、その点についてイメージを掴んでおこう。

ここでは、2つのディレクトリ a と b 【図 い】を合成するときの概念的な捉え
方を示す。

---[図 い]------------------------------------------------------------

 +--- ディレクトリ a/ ---+     +--- ディレクトリ b/ ---+
 |                       |     |                       |
 |    OSM                |     |    OSM                |
 |    foo                |     |    hoge               |
 |    bar                |     |    hero               |
 |                       |     |                       |
 +-----------------------+     +-----------------------+
----------------------------------------------------------------------

透明シートのように重ねて、

●Linux Unionfs の準備
LinuxにおけるUnionfsの実装【註 ろ】は、
A Stackable Unification File System
http://www.fsl.cs.sunysb.edu/project-unionfs.html

---[註 ろ]------------------------------------------------------------
Linuxには和集合ディレクトリを作ると言う意味での Unionfs の実装がいくつも
出てきている。Part3で触れるFUSEをベースにした Unionfs が2つ(あるいはそれ
以上)あり、それぞれ合成概念や機能が微妙に異なったりする。ここでは、「A
Stackable Unification File System」のものを便宜上 Linux Unionfs と呼ぶ。
----------------------------------------------------------------------

で入手することができる。Linux Unionfsの挙動を確かめるにはKNOPPIXを利用す
るのが手軽だろう。本誌2006年9月号にも収録されたKNOPPIX 5.0.1日本語版を起
動したものと仮定して説明する。

おおざっぱなイメージとしては、

	* a/ と b/ を足し算した結果を別のディレクトリ(たとえば u/) に
	  持ち込む、
	* 要素となるディレクトリの複数に同名のファイルがあった場合は
	  どのディレクトリのものを優先的に見せるかを優先順位で決める

というのがこの Unionfs の合成イメージである。

ところで、KNOPPIX環境自体もunionfsによって合成されたディレクトリツリーを
利用している。KNOPPIXを起動し、「ターミナル」を開き su コマンドでスーパー
ユーザになる。

root@ttyp1[~]# mount -tunionfs
/UNIONFS on /UNIONFS type unionfs (rw,dirs=/ramdisk=rw:/KNOPPIX=ro,delete=whiteout)


このため、unionfsで合成されたディレクトリ内にさらにunionfsマウントを行な
うとファイルシステムがハングするので注意すること。
    ============================
書き込み可能な /ramdisk で実験を行なう。

--------------------------------------------------------------ここから
# mkdir /ramdisk/uniontest
# cd /ramdisk/uniontest
# mkdir a b u
# touch a/{foo,bar} b/{hoge,hero}
# echo This is in A > a/OSM
# echo B dayo > b/OSM
# ls -l a b u
a:
合計 4
-rw-r--r-- 1 root root 13 2006-08-18 10:58 OSM
-rw-r--r-- 1 root root  0 2006-08-18 10:58 bar
-rw-r--r-- 1 root root  0 2006-08-18 10:58 foo

b:
合計 4
-rw-r--r-- 1 root root 7 2006-08-18 10:58 OSM
-rw-r--r-- 1 root root 0 2006-08-18 10:58 hero
-rw-r--r-- 1 root root 0 2006-08-18 10:58 hoge

u:
合計 0
--------------------------------------------------------------ここまで

ここで、a/ と b/ を合成したものを u/ にマウントしてみる。

--------------------------------------------------------------ここから
# mount -t unionfs -o dirs=a:b unionfs u
# ls -l u
合計 4
-rw-r--r-- 1 root root 13 2006-08-18 10:58 OSM
-rw-r--r-- 1 root root  0 2006-08-18 10:58 bar
-rw-r--r-- 1 root root  0 2006-08-18 10:58 foo
-rw-r--r-- 1 root root  0 2006-08-18 10:58 hero
-rw-r--r-- 1 root root  0 2006-08-18 10:58 hoge
# cat u/OSM
This is in A
--------------------------------------------------------------ここまで

同名のファイル OSM は a/ のものが見えている。mount 時に指定したディレク
トリ群のうち先に指定したものが優先順位の高いディレクトリとなる。優先順位
を見るには unionctl コマンドを利用する。

--------------------------------------------------------------ここから
# unionctl u --list
        /ramdisk/uniontest/a (rw-)
        /ramdisk/uniontest/b (rw-)
--------------------------------------------------------------ここまで

デフォルトではマウントする要素ディレクトリは書き込み可能だが、任意のディ
レクトリを読み取り専用にすることができる。mount時に指定する要素ディレク
トリに =rw または、=ro を付加すればよい。最左辺のディレクトリをrwにする
よう注意する。

--------------------------------------------------------------ここから
# umount u
# mount -t unionfs -o dirs=a=rw:b=ro unionfs u
--------------------------------------------------------------ここまで

この状態で、本来bにしかないファイルを削除してみる。

--------------------------------------------------------------ここから
# \rm u/hoge			(unionディレクトリにてhogeを消去)
# ls -la a b u			(-aオプションに注意)
a:
合計 4
drwxr-xr-x 2 root root 120 2006-08-18 11:03 .
drwxr-xr-x 5 root root 100 2006-08-18 10:55 ..
-rwxr-xr-x 1 root root   0 2006-08-18 11:03 .wh.hoge
-rw-r--r-- 1 root root  13 2006-08-18 10:58 OSM
-rw-r--r-- 1 root root   0 2006-08-18 10:58 bar
-rw-r--r-- 1 root root   0 2006-08-18 10:58 foo

b:
合計 4
drwxr-xr-x 2 root root 100 2006-08-18 11:02 .
drwxr-xr-x 5 root root 100 2006-08-18 10:55 ..
-rw-r--r-- 1 root root   7 2006-08-18 10:58 OSM
-rw-r--r-- 1 root root   0 2006-08-18 10:58 hero
-rw-r--r-- 1 root root   0 2006-08-18 11:02 hoge

u:
合計 4
drwxr-xr-x 2 root root 120 2006-08-18 11:03 .
drwxr-xr-x 5 root root 100 2006-08-18 10:55 ..
-rw-r--r-- 1 root root  13 2006-08-18 10:58 OSM
-rw-r--r-- 1 root root   0 2006-08-18 10:58 bar
-rw-r--r-- 1 root root   0 2006-08-18 10:58 foo
-rw-r--r-- 1 root root   0 2006-08-18 10:58 hero
--------------------------------------------------------------ここまで

aディレクトリに .wh.hoge というドットファイルができ、b/hoge を見えなくし
ている。下層のものを見えなくする処理をホワイトアウトという。ためしに
a/.wh.hero を作ると u/hero も見えなくなる。

--------------------------------------------------------------ここから
# touch a/.wh.hero
# ls u
OSM  bar  foo
--------------------------------------------------------------ここまで





●BSD unionfsの準備

4.4BSDで導入された Unionfs は、その後FreeBSD/NetBSDによって少しずつ手が
加えられ現在に至っている【註 は】。
---[註 は]------------------------------------------------------------
FreeBSDのUnionfsの不十分な部分を改善するパッチが提案されている。
詳しくはPart2参照。実験を行なうのであれば標準状態のUnionfsでも問題ない。
ただし、Unionfsで無限参照を発生させるような操作ミスをするとハングするの
で練習は実用機以外で行なうなど注意が必要だ。
----------------------------------------------------------------------

BSD unionfsは Linux のものと合成概念が異なる。こちらは、基本となるディレ
クトリの上(あるいは下)に別のディレクトリを重ねていく感じだ。BSD unionfsの
挙動の確認も【図 い】を想定したもので行なってみよう。スーパーユーザにな
り適当な作業ディレクトリを作る。BSD Unionfsの場合は結果を含ませるディレ
クトリを作らせる必要はないので、bをマウント先ディレクトリとする

--------------------------------------------------------------ここから
# mkdir /tmp/uniontest
# cd /tmp/uniontest
# mkdir a b
# touch a/{foo,bar} b/{hoge,hero}
# echo This is in A > a/OSM
# echo B dayo > b/OSM
# ls -l a b
a:
total 1
-rw-r--r--  1 root  wheel  13 Aug 18 14:19 OSM
-rw-r--r--  1 root  wheel   0 Aug 18 14:19 bar
-rw-r--r--  1 root  wheel   0 Aug 18 14:19 foo

b:
total 1
-rw-r--r--  1 root  wheel  7 Aug 18 14:19 OSM
-rw-r--r--  1 root  wheel  0 Aug 18 14:19 hero
-rw-r--r--  1 root  wheel  0 Aug 18 14:19 hoge
--------------------------------------------------------------ここまで

mount -t unionfs で Unionfs マウントを行なう点は Linux と同じだが、マウン
トポイントとなるディレクトリに上に載せたいディレクトリを重ねる。

--------------------------------------------------------------ここから
# mount -t unionfs /tmp/uniontest/a b
# ls -l b
total 1
-rw-r--r--  1 root  wheel  13 Aug 18 14:27 OSM
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 bar
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 foo
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 hero
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 hoge
# cat b/OSM
This is in A
--------------------------------------------------------------ここまで

ここで下層(b)にしかないファイル hoge を消してみる。
--------------------------------------------------------------ここから
# rm b/hoge
# ls -l b
total 1
-rw-r--r--  1 root  wheel  13 Aug 18 14:27 OSM
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 bar
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 foo
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 hero
--------------------------------------------------------------ここまで

上層の要素ディレクトリ a/ には、下層の hoge をホワイトアウトするエントリ
ができるが通常は見えない。
--------------------------------------------------------------ここから
# ls -l a
-rw-r--r--  1 root  wheel  13 Aug 18 14:27 OSM
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 bar
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 foo
--------------------------------------------------------------ここまで

ls の -W オプションで見ることができる。

--------------------------------------------------------------ここから
# ls -lW a
total 1
-rw-r--r--  1 root  wheel  13 Aug 18 14:27 OSM
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 bar
-rw-r--r--  1 root  wheel   0 Aug 18 14:27 foo
w---------  0 root  wheel   0 Jan  1  1970 hoge
--------------------------------------------------------------ここまで

ファイル属性の w は whiteout というファイルタイプを示すもので、Unionfsの
要素ディレクトリとしてマウントされたときに、下層のファイルを見せなくする
意味を持つ。上層にhogeファイルを作れば自動的に通常ファイルに変わる。
whiteout属性のファイルを消すには rm の -W オプションを使う。

--------------------------------------------------------------ここから
# rm a/hoge
rm: b/hoge: No such file or directory
# rm -W a/hoge
# ls b
OSM   bar   foo   hero  hoge
--------------------------------------------------------------ここまで


■
■cloopのはたらき
■

ファイルそのものをディスクイメージとして捉えるものに loop デバイス
(Linux)、vnode ディスク(FreeBSD/NetBSD)があるが、デバイスファイルとして圧
縮ファイルを利用できるようにしたものがcloopである。

仮に圧縮してあるイメージを foo.img とすると、次のようにして中に格納されて
いるファイルシステムをマウントすることができる。

Linuxの場合
--------------------------------------------------------------ここから
# insmod cloop.o file=foo.img
# mount -t <FSタイプ> /dev/cloop <マウントポイント>
--------------------------------------------------------------ここまで

FreeBSDの場合
--------------------------------------------------------------ここから
# kldload geom_uzip
# mount -t <FSタイプ> \
     /dev/`mdconfig -a -t vnode foo.img`.uzip <マウントポイント>
--------------------------------------------------------------ここまで

このように、UnixファイルシステムあるいはCDのISOイメージを圧縮したものを
直接マウントできるようにすることで、CDのように限られた容量のものにより多
くの内容を詰め込むことができる。

■
■メモリベースのファイルシステム
■

読み取り専用メディアの上に、書き込むことのできるディレクトリを重ねること
でファイル保存ができるようにしている。そのための「必ず書き込めるディスク」
を作成するために主記憶を利用したファイルシステムが使われる。

メモリベースのファイルシステムは、主記憶、swap、補助記憶などのいわゆる
「メモリ」全般を利用できるが、主記憶を利用するものがブータブルCDで利用さ
れる。Linuxの場合は tmpfs、FreeBSDの場合は malloc タイプのメモリファイル
システムでこれを構築する。

以下の例は32MBの領域を確保して /mem にマウントする例である。

【Linux】
# mount -t tmpfs -o size=32m /mem

【FreeBSD】
# mdmfs -M -s 32m md /mem

■
■うまく組み合わせて1CD環境を作ろう
■

Part1で述べた Unionfs, cloop, メモリベースのファイルシステムをうまく融合
させると、カスタマイズ自在なミニミニ環境を作ることができる。Part2ではこれ
らの組み合わせの実用的な適用例として、1CD環境を作成する例を順を追って見て
いこう。


---[図 に]------------------------------------------------------------
----------------------------------------------------------------------
参考文献

http://www.usenix.org/publications/library/proceedings/neworl/full_papers/mckusick.a


yuuji@gentei.org
Fingerprint16 = FF F9 FF CC E0 FE 5C F7 19 97 28 24 EC 5D 39 BA
HIROSE Yuuji - ASTROLOGY / BIKE / EPO / GUEST BOOK / YaTeX [Tweet]