Amazon EC2 で手元のホストとファイルを共有する

Amazon EC2 はVMを好きなタイミングで好きなだけ使うことができるので、複数のサーバを使う分散システムの検証環境として非常に使いやすい*1。費用を計算してみても、自宅でクラスタを動かすことを考えれば、十分安く上がりそうである。


しかし、VMを起動するたびに環境を設定したり、新しいテストを実行するたびにファイルを配ったりするのは面倒なので、ファイルを共有したくなる。
通信の遅延がかなり大きいので、EC2上でssh越しにファイルを編集するのも少々つらい。


そこで、手元のホストとホームディレクトリを共有する。さらに、一度転送したデータはキャッシュさせる。
共有ホームディレクトリ環境の管理方法と組み合わせれば、便利に使えるに違いない。

戦略

ファイル共有には NFSv4 over ssh を使う。NFSv4はポート番号を1つしか使わない(portmapperも要らない)ので、ssh越しで使いやすい。
これに FS-Cache を組み合わせて、データをキャッシュさせる。FS-Cache は Linux 2.6.30 から組み込まれている機能で、メモリだけでなくローカルディスクも使ってデータをキャッシュできるようにする。

NFSv4の設定

手元のホストでは、NFSv4サーバをセットアップしておく*2。 /etc/exportsでは127.0.0.1からのmountを許可しておく。


次にEC2でVMを立ち上る。ディスクイメージには "instance-store" 版のAmazon Linuxを使う。"ebs" 版ではキャッシュデータを置くローカルストレージが使えない*3


VMが立ち上がったら、sshでログインする。このときに、以下のように2049番ポートを remote port forwarding しておく:

ssh -R2049:127.0.0.1:2049 ec2-user@ec2-host.compute-1.amazonaws.com


ログインしたら、nfs-utilsをインストールする。また、後述するcachefilesdをコンパイルするために、gccもインストールしておく:

yum install nfs-utils gcc


NFSv4サーバとuidを合わせたユーザーを作っておくと、ユーザ管理が簡単になるので便利だろう。

# uidはサーバ側に合わせる
useradd -m -u 502 -d /home/viver viver


併せてidmapdの設定が必要になるかもしれない。/etc/idmapd.conf で、"Domain" をサーバの idmapd.conf と同じにしておく:

[General]
# The following should be set to the local NFSv4 domain name
# The default is the host's DNS domain name.
#Domain = local.domain.edu
Domain = localdomain


rpc_pipefsをmountし、idmapdを起動する。

mount -t rpc_pipefs rpc_pipefs /var/lib/nfs/rpc_pipefs
service rpcidmapd restart


ここで試しにmountしてみる。mountできなければ、何かが間違っている。NFSv4サーバ/クライアント双方のdmesgを見るなどして修正する。

mount -t nfs4 127.0.0.1:/ /mnt
umount /mnt

キャッシュの設定

次にFS-Cacheの設定をする。
FS-Cacheを有効にするには、cachefilesdというパッケージをインストールする必要がある。現時点ではyumにバイナリパッケージが用意されていないので、Webサイトからダウンロードして自前でコンパイルする。実は./configureさえ無いので、軽くソースを眺める必要があるかもしれない。

wget http://people.redhat.com/~dhowells/fscache/cachefilesd-0.10.tar.bz2
tar jxvf cachefilesd-0.10.tar.bz2
cd cachefilesd-0.10
make
sudo cp cachefilesd /usr/sbin/
sudo cp cachefilesd.conf /etc/


/etc/cachefilesd.conf を編集する。最低限、キャッシュを保存するディレクトリと、SELinuxの設定を書き換える。
キャッシュの保存先はローカルディスク(/media/ephemeral0)とする。SELinuxの設定はコメントアウトする。

#dir /var/fscache
dir /media/ephemeral0/fscache
tag mycache
brun 10%
bcull 7%
bstop 3%
frun 10%
fcull 7%
fstop 3%

# Assuming you're using SELinux with the default security policy included in
# this package
#secctx system_u:system_r:cachefiles_kernel_t:s0


キャッシュを保存するファイルシステムはuser_xattrが有効になっている必要があるらしいので、remountして有効にしておく。

mount -o remount,user_xattr /media/ephemeral0
mkdir /media/ephemeral0/fscache
/usr/sbin/cachefilesd


最後に、キャッシュを有効にしてNFSv4をmountする。キャッシュを有効にするには -o fsc オプションを付ける:

mount -t nfs4 -o fsc 127.0.0.1:/ /mnt
mount --bind /mnt/home/viver /home/viver


いくつかファイルを読み込み、キャッシュの保存先ディレクトリを見てみると、サイズが膨らんでいた。きっとキャッシュが効いているのだろう。

$ du -sh /media/ephemeral0/fscache
261M	/media/ephemeral0/fscache/

*1:それにしてもInTriggerは便利そうだなぁ…などと。[http://supercell.osuosl.org/:title=Supercell] にも期待。

*2:NFSv4の設定はNFSv3と似ているようで全然違うのでややこしい。

*3:-b "/dev/sdb=ephemeral0" などとオプションを付けると、ebs版でもローカルディスクを使えるとのこと。 http://twitter.com/j3tm0t0/status/36354896789901312