第18章 NFSサーバーの構築と運用
LPIC-2 209.2 相当
前章のSambaと並んで、Unix/Linux環境で長く使われている標準的なファイル共有方式がNFS(Network File System)です。
NFS — Unix系の標準的なファイル共有
サーバー側 /etc/exports
/srv/nfs/share 192.168.1.0/24(rw,sync,no_subtree_check)
$ sudo exportfs -a # /etc/exportsの内容を反映(正常時は無出力)
$ sudo systemctl restart nfs-kernel-server # Debian系のユニット名。正常時は無出力
$ showmount -e サーバーIP # 公開されている共有一覧を確認(クライアント側)
Export list for 192.168.1.10:
/srv/nfs/share 192.168.1.0/24
この行のこの値に注目: showmount -eの出力にあるExport list for ...以降に、実際にサーバーが公開している共有パスと、それぞれにアクセスを許可されているクライアント範囲が1行ずつ並びます。ここに目的の共有が表示されなければ、/etc/exportsの記述漏れか、exportfs -aの反映漏れが原因です。
nfs-kernel-serverはDebian系のサービス(ユニット)名です。RHEL系ではnfs-serverという名前になるため、sudo systemctl restart nfs-serverのように読み替えてください。
クライアント側でマウント
$ sudo mount -t nfs サーバーIP:/srv/nfs/share /mnt/nfs # 正常時は無出力
/etc/exportsのオプションのうち、rw(読み書き許可)/ro(読み取り専用)やsync/async(書き込み完了をどのタイミングでクライアントに通知するか)に加え、セキュリティ上重要なのが root_squash です。既定で有効になっており、クライアント側のrootユーザーによるアクセスを、サーバー側では権限の低い匿名ユーザー(nobody)に読み替えます。no_root_squash を指定するとこの保護が無効になるため、信頼できるホスト以外には設定すべきではありません。
sec=krb5)にも対応します。新規構築では特別な理由がない限りNFSv4を選ぶのが一般的です。
NFSではユーザーID(UID)・グループID(GID)が数値のままネットワーク越しに伝わる点も重要です。サーバー側とクライアント側で同じUID/GIDが異なるユーザーに割り当てられていると、意図しないユーザーにファイルの所有権が見えてしまう問題が起こります。複数サーバーでNFSを使う環境では、LDAPのような仕組みでUID/GIDを一元管理し、サーバー間でズレが生じないようにするのが実務上のベストプラクティスです。
$ rpcinfo -p サーバーIP # サーバー上で稼働しているRPCサービスとポート番号を確認(NFSv3のトラブルシューティングに有用)
program vers proto port service
100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100005 3 tcp 20048 mountd
100021 4 tcp 38621 nlockmgr
$ nfsstat -c # クライアント側のNFS統計情報を表示
Client rpc stats:
calls retrans authrefrsh
128394 3 128401
Client nfs v4:
null read write commit open close
0.00% 42.18% 11.30% 2.01% 6.44% 6.30%
この行のこの値に注目: rpcinfo -pのNFSv3環境では、portmapper(111番)に加えてnfs・mountd・nlockmgrなどが、それぞれ異なる(多くの場合ランダムな)ポート番号で待ち受けています。これがNFSv3でファイアウォール設定が煩雑になる理由です。nfsstat -cのretrans(再送回数)がcallsに対して大きい割合を占めている場合、ネットワーク品質の問題やサーバー側の応答遅延が疑われます。
| /etc/exportsの主なオプション | 意味 |
|---|---|
rw / ro | 読み書き許可 / 読み取り専用 |
sync / async | 書き込みをディスクに確定させてから応答するか(sync、安全)/すぐ応答するか(async、高速だが障害時にデータ消失の可能性) |
root_squash / no_root_squash | クライアント側rootの権限を匿名ユーザーに読み替えるか(既定はroot_squashで有効) |
all_squash | rootに限らず、すべてのユーザーを匿名ユーザーに読み替える。読み取り専用の公開共有などで使用 |
NFSv4のディレクトリ構成とアクセス制限
NFSv4では、サーバー側で1つの「疑似ファイルシステム」のルート(fsid=0を指定したエクスポート)を頂点とし、実際に共有したいディレクトリをその配下にbindマウントする構成が一般的です。クライアントからは、この疑似ルートを基準にした相対パスでマウントします。
/etc/exports(NFSv4向けの構成例)
/export 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)
/export/share 192.168.1.0/24(rw,sync,bind)
アクセス制限は/etc/exportsで指定するホスト・サブネットの範囲に加えて、NFSサーバーがTCP Wrappers(/etc/hosts.allow・/etc/hosts.deny)にも対応している場合、portmapやmountdといったサービス名を指定して二重にアクセス制御をかけることもできます。
NFSv4のユーザー名前解決(idmapd)
NFSv3までは、ファイルの所有者情報を数値のUID/GIDのままやり取りしていましたが、NFSv4ではユーザー名@ドメイン名という文字列形式でやり取りする点が大きく異なります。この変換を担うのがrpc.idmapdデーモンで、設定は/etc/idmapd.confに記述します。
/etc/idmapd.conf の主な設定項目
[General]
Domain = example.com
[Mapping]
Nobody-User = nobody
Nobody-Group = nogroup
Domainの値がサーバー側とクライアント側で一致していないと、正しくマッピングできたはずのユーザーがnobodyとして見えてしまうというトラブルが典型的です。ファイルの所有者が急にnobodyになってしまった場合は、まずサーバーとクライアントのidmapd.confのDomain設定が一致しているかを確認します。
Kerberosを使った強固な認証(sec=krb5)
既定のNFSは、クライアントが名乗るUID/GIDをサーバー側がそのまま信用する「AUTH_SYS」という認証方式を使っており、クライアント側さえ細工すれば別のユーザーになりすませてしまう弱点があります。より強固なセキュリティが必要な環境では、Kerberosによる認証(sec=krb5)を使います。
サーバー側 /etc/exports(Kerberos認証を要求する例)
/srv/nfs/secure 192.168.1.0/24(rw,sync,sec=krb5)
クライアント側でのマウント(正常時は無出力)
$ sudo mount -t nfs4 -o sec=krb5 サーバーIP:/secure /mnt/secure
Kerberosのチケットが取得できていない状態でこのマウントを試みると、次のようなエラーになります。
$ sudo mount -t nfs4 -o sec=krb5 サーバーIP:/secure /mnt/secure
mount.nfs4: Operation not permitted
この行のこの値に注目: Operation not permittedという一見分かりにくいエラーは、sec=krb5指定時にはKerberosの本人確認チケット(kinitで取得)が必須であることが原因のことが多く、klistで有効なチケットを保持しているかをまず確認します。
| secオプションの値 | 意味 |
|---|---|
sys(既定) | クライアントが名乗るUID/GIDをそのまま信用する(AUTH_SYS) |
krb5 | Kerberosによる本人確認のみ行う |
krb5i | 本人確認に加え、通信の完全性(改ざん検知)も保証する |
krb5p | 本人確認・完全性に加え、通信内容自体を暗号化する(最も安全だが最もオーバーヘッドが大きい) |
Kerberos認証を使うには、NFSサーバー・クライアントの双方がKerberos KDC(鍵配布センター)と連携できる状態になっている必要があり、単体のオプション追加だけでは完結しない点に注意してください。試験対策としては、sec=オプションの4段階(sys/krb5/krb5i/krb5p)でセキュリティレベルが変わることを押さえておけば十分です。
マウントオプションのチューニング
| オプション | 意味 |
|---|---|
rsize / wsize | 1回の読み込み・書き込みで転送するデータサイズ。大きくすると高速化することがあるが、ネットワーク品質によっては逆効果になることも |
timeo | 応答がない場合に再送を試みるまでのタイムアウト時間(0.1秒単位) |
retrans | 再送を試みる回数の上限 |
ac / noac | 属性キャッシュを使うか(既定はac=使う)。noacは常に最新の状態をサーバーへ問い合わせるため、複数クライアントからの同時書き込みに強い代わりに性能は落ちる |
$ sudo mount -t nfs -o rsize=32768,wsize=32768,timeo=30 サーバーIP:/data /mnt/data # 正常時は無出力
実際にどのオプションでマウントされたかは、mountコマンド(引数なし)や/proc/mountsで確認できます。
$ mount | grep /mnt/data
サーバーIP:/data on /mnt/data type nfs (rw,relatime,vers=3,rsize=32768,wsize=32768,timeo=30,...)
この行のこの値に注目: 指定していないオプション(vers=3やrelatimeなど)もカーネル側の既定値として補完され、実際に有効になっている全オプションがここに表示されます。指定したrsize・wsize・timeoの値が意図通り反映されているかは、この出力で必ず確認します。
SambaとNFSの使い分け
| 状況 | 選択 |
|---|---|
| Windowsクライアントと共有したい | Samba |
| Linux/Unixサーバー間で共有したい | NFS |
| 混在環境 | 両方を並行して提供することも多い |
マウントの動作確認とトラブルシューティング
クライアント側でNFS共有をマウントできない、あるいは急に応答がなくなった場合、まずサーバー側でその共有が正しくエクスポートされているかを確認します。
$ showmount -e サーバーIP # サーバーが公開しているNFS共有の一覧を確認
clnt_create: RPC: Port mapper failure - Unable to receive: errno 110 (Connection timed out)
$ sudo mount -t nfs サーバーIP:/data /mnt/data
mount.nfs: Connection timed out
$ sudo exportfs -ra # /etc/exportsの変更後、サーバー側で再エクスポート(正常時は無出力)
この行のこの値に注目: clnt_create: RPC: Port mapper failure ...やmount.nfs: Connection timed outは、いずれもサーバー側のNFS関連サービスが起動していない、あるいはファイアウォールで該当ポートが塞がれている場合に典型的に出るエラーです。この場合、サーバー側でsystemctl status nfs-kernel-serverやrpcinfo -pで稼働状況を確認し、続いてexportfs -raで/etc/exportsの内容を再反映してから、クライアント側で再度マウントを試みるという切り分け手順になります。
NFSは既定で「hard」マウント(サーバーが応答するまで処理をブロックし続ける)になっており、サーバー障害時にクライアント側のプロセスがハングしたように見えることがあります。応答性を優先したい一部の用途では、タイムアウト時にエラーを返す「soft」マウントを選ぶこともありますが、書き込み中のデータ破損リスクとのトレードオフがあるため、用途に応じて慎重に選択する必要があります。
永続的なマウント設定と自動マウント
再起動後もNFS共有を自動的にマウントしたい場合は、/etc/fstabに記述するのが基本です。ただしNFSサーバーがネットワーク越しに存在するという性質上、ローカルディスクとは違った注意点があります。
サーバーIP:/data /mnt/data nfs defaults,_netdev 0 0
_netdevオプションは「ネットワークが利用可能になってからマウントを試みる」ことをシステムに伝えるもので、これを付けないとネットワークインターフェースが起動しきる前にマウントが試みられて失敗する場合があります。常時接続とは限らないリモート共有では、第4章で扱ったautofsによるオンデマンドマウントを使う方が、サーバー側の一時的な不調がクライアントの起動プロセス全体を止めてしまうリスクを避けられ、より堅牢な構成になることもあります。