2段階のNFSマウントをする方法


直接アクセスできないネットワークにあるNFSサーバをNFSでマウントすることはできないか試行錯誤してみた。

普通にCentOS7やSolaris11からやってみたところ、NFSマウントした領域のNFS exportでの公開はnfsd側から「Cannot export /mnt, possibly unsupported filesystem or fsid= required」とか、「Invalid filesystem」とか言われて設定できない。

これはuser-spaceで動作するnfsdを使えば回避できるんじゃないかと探してみた結果、unfs3というものを発見。ソースコードは https://github.com/unfs3/unfs3

Linux,FreeBSD,Solaris,AIX,Irix,MacOSXで動く以外に、Windows上でも制限ありで動作するとのこと。

Windows上で動かした場合は、unfsdが使用するWindowsユーザを1つ割り当てる形になるので、NFS経由のアクセスは全てそのWindowsユーザがアクセスしている、という扱いになるようだ。

あと、このunfs3はNFS ver3のみ使え、NFS v4やNFS v2でのアクセスには対応していない。また、NFS v3でもREADDIRPLUS(属性付きディレクトリの読み取り)周りは実装していないとのこと。

READDIRPLUSはOracle/Solarisのドキュメントによればlsコマンドなどでディレクトリ内のファイル一覧を表示させる動作を高速化するためのものなので、まぁ、なくてもなんとかなる感じのもの。

属性付きディレクトリの読み取り
NFS バージョン 3 では、READDIRPLUS と呼ばれる操作があります。たとえば、ls や ls -l などの、大部分の READDIR が READDIRPLUS コールとして発行されます。バージョン 3 で ls -l コマンドを実行すると、ディレクトリ内の名前リストと共に、ファイルハンドルと属性が返されます。バージョン 2 では、名前が最初に返され、ファイルハンドルと属性を取得するには、続いてサーバーを呼び出す必要があります。
バージョン 3 の READDIRPLUS 操作の利点は、ファイルごとに GETATTR 要求を送信する必要がないため時間が短縮され、ls と ls -l の速度が同程度になることです。

要件は満たせそうなので、とりあえずテスト用CentOS7環境でunfs3を動作させてみる。

準備

環境をインストール

# yum install git
# yum groupinstall "開発ツール"

コンパイル

まず、ソースコードの入手

$ git clone https://github.com/unfs3/unfs3.git

READMEにあるとおりbootstrap&configureを実行

$ cd unfs3/unfs3
$ ./bootstrap
$ ./configure

そしてmake

$ make
for i in Config ; do (cd $i && make all) || exit; done
make[1]: ディレクトリ `/root/unfs3/Config' に入ります
gcc -g -O2 -Wall -W -I.. -I. -I..   -c -o lex.yy.o lex.yy.c
gcc -g -O2 -Wall -W -I.. -I. -I..   -c -o y.tab.o y.tab.c
ar crs lib.a lex.yy.o y.tab.o
make[1]: ディレクトリ `/root/unfs3/Config' から出ます
gcc -g -O2 -Wall -W  -D_GNU_SOURCE -I.   -c -o afsgettimes.o afsgettimes.c
gcc -g -O2 -Wall -W  -D_GNU_SOURCE -I.   -c -o afssupport.o afssupport.c
gcc -g -O2 -Wall -W  -D_GNU_SOURCE -I.   -c -o attr.o attr.c
attr.c: 関数 ‘get_free_bad_dir_entry’ 内:
attr.c:550:5: エラー: ‘for’ ループ初期化宣言は C99 モード内でのみ許可されてい ます
     for (int i = 0;i < BAD_DIR_CACHE_SIZE;i++) {
     ^
attr.c:550:5: 備考: オプション -std=c99 または -std=gnu99 をコードコンパイル時に使用してください
attr.c: 関数 ‘find_bad_dir_entry’ 内:
attr.c:573:5: エラー: ‘for’ ループ初期化宣言は C99 モード内でのみ許可されてい ます
     for (int i = 0;i < BAD_DIR_CACHE_SIZE;i++) {
     ^
make: *** [attr.o] エラー 1
$

エラーとなってしまいます。

これはコンパイル時のオプションに「-std=c99」を指定するようにして解決

$ export CPPFLAGS="-std=c99";./configure
$ make
<略>
$

インストールと設定

普通にmake installすると/usr/local以下にインストールされます。

# make install
/usr/bin/install -c -d /usr/local/sbin
/usr/bin/install -c -d /usr/local/share/man/man7
/usr/bin/install -c -d /usr/local/share/man/man8
/usr/bin/install -c unfsd /usr/local/sbin/unfsd
/usr/bin/install -c -m 644 ./Extras/tags.7 /usr/local/share/man/man7/tags.7
/usr/bin/install -c -m 644 ./unfsd.8       /usr/local/share/man/man8/unfsd.8
#

NFSで公開するディレクトリの設定は、普通のnfsdと同じく /etc/exports ファイルを使用。「-e」オプションで別のファイルを指定することも可能です。

注意点としては、Linuxだとホスト名指定に「*」とnetgroupが使用できず、ログに「unfsd[20479]: syntax error in ‘/etc/exports’, exporting nothing」といった出力が出てしまうという点です。

「*」については「0.0.0.0/0」で代替できます。

/etc/exports ファイルを編集した場合、変更にはexportfsコマンドは使用できません。

unfsdに対してHUPシグナルを送ることで反映されます。(kill -HUP unfsdのPID)

unfsdの起動は「/usr/local/sbin/unfsd」の実行、停止はunfsdへのTERMシグナル送信(kill -TERM unfsdのPID)です。

Solaris 11をNISクライアントにする


Solaris 環境からのNFS v4アクセスを確認するため、VMware上にSolaris 11をインストールした。

NISによるユーザIDの共通化も検証するため、NISクライアントの設定を行った。

NISクライアントにする設定は「domainname NISドメイン名」でNISのドメイン名を設定したあと「ypinit -c」で終わり。

つぎは/etc/nsswitch.confを編集して…と思ってvi /etc/nsswitch.confで開いてみると、手動で編集するな、という記載が…

マニュアルを探すと「Oracle Solaris 11.1 でのネームサービスおよびディレクトリサービスの作業」の「ネームサービススイッチの管理」があった。

「データベースのソースを切り替える方法」にある「svccfg -s system/name-service/switch」で入ったあと「listprop config」で現在の設定値を確認できる。

nsswitch.conf にあるいろんなエントリのうち、hostsとprinterしかない。

じゃぁ、手動で設定すればいいのかと「setprop config/passwd=”files nis”」と実行してみるとエラー。

じゃぁ、と「setprop config/password=”files nis”」に変えてみると設定成功

「setprop config/group=”files nis”」も実行。

「quit」で抜けて、「svcadm refresh name-service/switch」を実行するとシステムに反映されて、ls -l でみた場合の結果に反映された。

また、値が反映されると/etc/nsswitch.confの内容も書き換わる。