正直あまり使いたくないNFSを使わなければいけない状態に陥ってしまったので覚書。
前提環境(サーバ・クライアントとも)
- CentOS7
- Linux 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018
- NFSv4
サーバ側設定
/etc/exportsに書くだけ。または、ドロップインディレクトリ/etc/exports.d
配下にファイルを追加する。
/work 192.168.3.0/24(rw)
一つのディレクトリを複数のネットワークに公開するには、スペース区切りのリストにする。
/work 192.168.3.0/24(rw) 10.1.1.0/24(ro)
スペースは公開対象リストのデリミタとしての意味を持つため、例えば以下のように書き間違えると大変なことになる。
/work 192.168.3.0/24 (rw)
/work 192.168.3.0/24() *(rw)
上の2行は同じ意味。つまり、192.168.3.0/24のネットワークに対してデフォルト設定で公開し、全世界"<world>"に向けて"rw"その他デフォルト設定で公開するということになる。
公開先とオプションの"()"の間にスペースを入れてはいけない。まったく別の意味になる(と、マニュアルにも注意書きがある)。
主なオプション<サーバ側>(man exports
から抜粋)
-
secure
: 1024より小さいポート番号からのリクエストしか受け付けない。これがデフォルト。無効にするにはinsecure
を明示。 -
rw
: Read/Writeを可能にする。デフォルトはro
(read only)。 -
async
: NFSプロトコルでは同期が標準だがこれをあえて非同期にする(パフォーマンス向上、信頼性・一貫性犠牲にしたいとき)。デフォルトはsync
。 -
root_squash
: uid/gidが0、つまりrootユーザからのリクエストをanonymousに格下げ(squash)する。デフォルト有効で無効にするにはno_root_squash
を指定する。 -
all_squash
: root以外のユーザからのリクエストもanonymousに格下げ(squash)する。デフォルトはno_all_squash
。 -
anonuid
/anongid
: 格下げ(squash)する対象のuid/gidをそれぞれ指定する。
主なオプション<クライアント側>(man nfs
から抜粋)
-
nfsvers=n
: NFSプロトコルバージョンを指定する。 -
soft
/hard
: デフォルトはhard
で、NFSサーバダウン時に無限リトライ。soft
にするとリトライアウトあり。 -
timeo=n
: タイムアウト値を指定する。単位は1/10秒。TCP使用時のデフォルトは600(60秒)。 -
retrans=n
:soft
マウント時のリトライ回数を指定する。 -
intr
/nointr
: 下位互換性のため保持(無視)。 -
bg
/fg
: マウントをバックグラウンドかフォアグラウンドで実行するかを指定する。 -
retry=n
: マウントのリトライ時間を分単位で指定する。デフォルトはフォアグラウンドで2分、バックグラウンドでは10,000分(ほぼ1週間)。0に指定するとリトライなし。
主なコマンド
-
exportfs -a
: 設定されたディレクトリをすべて公開する。 -
exportfs -au
: 公開されたディレクトリをすべて非公開にする。 -
exportfs -v
: 公開されているディレクトリの詳細を表示する。 -
nfsstat -l
: NFS統計情報をリスト形式で出力する。 -
nfsstat -m
: NFSマウントの情報(オプション等)を出力する(クライアント側)。
NFSサーバダウン時の影響(fstab編)
NFSはいわゆる蜜結合なソリューションであり、常時マウントすべく/etc/fstab
にNFSマウントのエントリをdefaults
で記載しておくと、NFSサーバのダウン時に非常に困る。そして現場SEを以下のようなシチュエーションで苦労させることになる。
※昔のOS(CentOSだと6まで)ではfstab
ではなくnetfs
というサービスでNFSマウントさせていたが、現行バージョンでは必要なくなった模様。
db1:/work /tmp/work nfs defaults 0 0
OS起動時
マウント時のretry
オプション(デフォルト2分)でタイムアウトする(通常よりもサーバ起動にかかる時間が長くなる)。復旧後に手動でmount
しなおさなければならない。
マウント中
hard
マウントしていれば無限リトライし、復旧後はなにごともなかったかのように処理される。NFSファイルシステムにアクセスするプロセスはフリーズしたような状態となる(IOエラーにならず、典型的にはstat
関数が実行中のままになる)。このため、多数のプロセスが起動したままとなり、クライアント側リソースが食いつぶされていくことになる(例えばdf
コマンドもフリーズする)。
対応としてsoft
マウントすればIOエラーで異常終了させられるが、推奨はされていない(ファイルシステムの一貫性が大事)。どちらがよいかはアプリケーション設計も含めた決断になる。
アンマウント時
stat
がフリーズするので、umount
もフリーズする。umount --force
でタイムアウトまで待つか、リブートする前提でumount -l
で即時lazyアンマウントするしかない。
OS停止時
マウント・アンマウントもsystemd制御なのでumount
が90秒でタイムアウトしてそのままパワーオフすると想定される(少し時間はかかるがパワーオフはできる)。
NFSサーバダウン時の影響(autofs編)
特にOS起動時にNFSサーバがダウンしていた場合、手動での回復が運用的にNGであれば、autofs
サービスを使うのが一つの解となり得る(yum install autofs
)。
セットアップ
autofs
の構成はマスターとマップと呼ばれる2つのファイルからなる。
デフォルトでは"/etc/auto.master.d"がドロップインディレクトリなので、ここにファイルを追加する。
/- /etc/auto.master.d/auto.nfs -t 10 rw
書式は、マウントポイント (マップタイプ,フォーマット)マップファイル オプション
となる。マップタイプはデフォルトが"file"で、ほかには"program"や"ldap"なども指定できる。オプションにはマウントオプション("rw"など)等を指定できる("-"つきオプションはautofsに対するもので、"-"なしはmount -o
に渡される)。
ダイレクトマッピング(個別のディレクトリをフルパスで管理)する場合、マウントポイントには"/-"を指定する。そうでない場合、当該ディレクトリ配下は"autofs"の管理下となる(マウントされない限り配下には何も見えない状態)。
/tmp/work db1:/work
マップファイルの書式はマウントポイントディレクトリとマウントオプション(上記例では10秒アクセスがなければアンマウントし、書き込み可能)、マウントするデバイスを指定する。
systemctl start autofs
, systemctl enable autofs
しておく。
OS起動時
起動直後にdf
しても、指定したNFSファイルシステムはマウントされていない。当該ディレクトリにアクセスした際にオンデマンドでマウントされ、一定時間(デフォルト300秒で-t|--timeout
オプションでオーバーライド)アクセスがなければリソース解放(アンマウント)してくれる。
というわけで、これを使えばOS起動時にNFSサーバがダウンしていたとしても、対象ディレクトリにアクセスしない限りは問題ない。
マウント中
fstabでマウントしたときと同様になる(アクセス中プロセスは無限リトライでフリーズし、復旧後に継続処理)。
アンマウント(タイムアウト)時
fstabでマウントしたときと同様になる(NFSサーバ復旧後にアンマウント)。
OS停止時
これが厄介で、シャットダウンシーケンスが止まってしまう(autofs自体はデフォルトユニットファイル定義180秒タイムアウト、そのあとのumountで止まると推測)。これを避けるために、以下のようにNFSマウントを強制的に外す処理を入れておくのが吉。
[Unit]
Before=shutdown.target
[Service]
ExecStart=/usr/bin/umount -lat nfs4
[Install]
WantedBy=shutdown.target
これで一応はきれいにシャットダウン可能。
とにかく、NFSを使う以上、いろいろな意味でそれなりの覚悟が必要だということ。
NFSサーバ自体に高可用性を確保するか、必要な時にmount
して使い終わったらumount
するか、autofs
を使うか、、、できれば使わなくて済むのであればそれに越したことはない気もする。
参考
- RHEL公式ドキュメント
man nfsstat
man nfs
man exports
man exportfs
man auto.master
man automount