inotify 枯渇が本番障害を引き起こすメカニズム
inotify(inode notify)は Linux カーネルが提供するファイルシステムイベント監視機構です。ファイルの変更・作成・削除を非同期に検知できるため、Prometheus の各種エクスポーター、Datadog エージェント、Filebeat、systemd の .path ユニット、さらに VSCode や JetBrains IDE のリモート拡張機能まで、幅広いツールが内部的に inotify を利用しています。
inotify の動作はカーネルパラメーターで上限が定められており、主に以下の3つが問題になります。
- fs.inotify.max_user_watches:ユーザーあたりが設定できる watch(監視エントリー)の上限。デフォルト値はディストリビューションによって 8,192 〜 65,536 程度です。
- fs.inotify.max_user_instances:ユーザーあたりが作成できる inotify インスタンス(ファイルディスクリプタ)の上限。デフォルトは 128 です。
- fs.inotify.max_queued_events:1 インスタンスあたりのイベントキューの上限。デフォルトは 16,384 です。
これらのいずれかが満杯になると、新たな watch の登録は ENOSPC(”No space left on device”)というエラーで失敗します。エラーメッセージがディスク容量不足と同一の ENOSPC であるため、初見では原因特定が遅れがちです。アプリケーションによっては例外を握りつぶして無音で動作不能になるケースもあり、本番環境で発覚するまで長時間気づかれないことがあります。
枯渇の兆候と初動診断
inotify 枯渇が疑われる典型的な兆候を挙げます。
- ログ収集エージェントが特定ディレクトリの新着ログを取得しなくなる
- CI/CD パイプラインのファイル変更検知がタイムアウトする
- systemd の
.pathユニットが起動直後に失敗ログを残す - アプリケーションのエラーログに
inotify watch limit reachedやENOSPCが出現する - ファイル監視を使うプロセスの CPU 使用率が突然上昇してポーリングにフォールバックする
まず現在の上限値を確認します。
# 現在の上限値を確認
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances
sysctl fs.inotify.max_queued_events
上限値の確認だけでは「今どれだけ消費されているか」はわかりません。使用量の確認には /proc ファイルシステムを参照します。
# inotify インスタンスを保持しているファイルディスクリプタの総数を確認
find /proc/*/fdinfo -name "*" 2>/dev/null \
| xargs grep -l "inotify" 2>/dev/null \
| wc -l
この数値が max_user_instances に近い場合はインスタンス枯渇、後述の watch 数合計が max_user_watches に近い場合は watch 枯渇が疑われます。
消費源の特定:どのプロセスが watch を使い切っているか
枯渇の根本原因を特定するには、どのプロセスが多くの watch を消費しているかを把握する必要があります。各プロセスの /proc/<pid>/fdinfo/ 内には inotify インスタンスの watch エントリー(wd: 行)が記録されており、これを集計することでプロセスごとの消費量を算出できます。
# プロセスごとの inotify watch 数を多い順に表示
for pid in $(find /proc -maxdepth 1 -name '[0-9]*' -printf '%f\n' 2>/dev/null); do
watches=$(grep -c '^wd:' /proc/"$pid"/fdinfo/* 2>/dev/null || echo 0)
comm=$(cat /proc/"$pid"/comm 2>/dev/null || echo unknown)
echo "$watches $pid $comm"
done | sort -rn | head -20
watch 数の多いプロセスが上位に並びます。一般的には以下のツールが大きな消費源になります。
- ログ収集エージェント(Filebeat、Fluentd、Vector など):監視対象ディレクトリが多いほど watch を消費します。ディレクトリの再帰監視を有効にしているとさらに消費量が増えます。
- 監視エージェント(Datadog Agent、node_exporter など):プロセスやファイルを常時監視するため、常に一定数の watch を消費します。
- 開発ツール(webpack の watch モード、jest の watch モード、VSCode remote など):開発用サーバーを本番環境で起動したままにしている場合に問題になります。
- コンテナランタイム:コンテナ数が多いノードでは、各コンテナ内プロセスの watch 数がホストカーネルの上限に加算されます(名前空間による分離が行われない点については後述します)。
恒久チューニング設計:上限値の根拠と設定方法
一時的な対処として sysctl -w fs.inotify.max_user_watches=524288 のようにランタイム変更できますが、再起動後に元に戻るため恒久対処にはなりません。本番環境では /etc/sysctl.d/ 配下にファイルを作成して永続化します。
# /etc/sysctl.d/99-inotify.conf として作成
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512
fs.inotify.max_queued_events = 32768
作成後、再起動不要で即時反映させるには以下のコマンドを実行します。
sudo sysctl --system
--system オプションは /etc/sysctl.d/、/run/sysctl.d/、/usr/lib/sysctl.d/ を優先度順にすべて読み込みます。特定ファイルを -p で指定するよりも優先度の整合性を保ちやすく、本番環境での適用に適しています。反映された値は sysctl fs.inotify.max_user_watches で確認します。
上限値の設計方針は次のとおりです。
- max_user_watches:診断コマンドで計測した現在の消費量の 3〜4 倍を目安にします。Filebeat などは 1 エージェントあたり数万 watch を消費することがあるため、512,288 前後がよく採用される値です。
- max_user_instances:inotify を使うプロセス数(マルチスレッドの場合はスレッド数)に合わせます。デフォルト 128 では不足しやすいため、256〜512 に引き上げると安定します。
- max_queued_events:大量のファイル変更が短時間に発生する環境(ビルドサーバー、デプロイ時の展開先など)では 32,768〜65,536 に引き上げると、イベントの溢れ(
IN_Q_OVERFLOW)を抑制できます。
メモリへの影響は軽微です。watch 1 エントリーあたりのカーネル内メモリは数十バイト程度のため、max_user_watches を 524,288 に設定してすべて埋まったとしても、増加分は数十 MB 程度にとどまります。
コンテナ・Kubernetes 環境での落とし穴(2026 年現行差分)
inotify の上限はカーネルパラメーターであり、Linux 名前空間(namespace)では分離されません。コンテナ内で inotify watch を作成した場合、その消費量はホストカーネルの上限に加算されます。
コンテナ内で sysctl fs.inotify.max_user_watches を変更しても、それはコンテナ内から参照できる値を書き換えるだけであり、実際の上限はホストカーネルの値が適用されます。Kubernetes のノードに多数のワークロードが乗っている場合、各コンテナ内のプロセスが消費する watch 数がノード全体で合算されるため、ノード単位での上限設計が必要です。
Kubernetes 環境でノード全体の sysctl を設定する方法は主に 2 種類あります。
- ノードプロビジョニング時に設定する:cloud-init、Ansible、Terraform などのプロビジョニングツールで
/etc/sysctl.d/99-inotify.confを展開し、ノード起動時から有効にします。マネージド Kubernetes(EKS、GKE、AKS)ではノードグループのカスタム起動スクリプト(user-data)で対処します。 - DaemonSet で設定する(privileged):特権コンテナで
sysctl -wを実行する DaemonSet を配置する手法もありますが、PodSecurityAdmission などのセキュリティポリシーとの兼ね合いで採用できない環境もあります。
2026 年時点の主要ディストリビューション(Ubuntu 24.04 LTS、RHEL 9 系など)では、以前と比べてデフォルト値が引き上げられているケースがあります。ただし、デフォルト値はカーネルバージョンやディストリビューションのパッチポリシーによって差異があるため、実環境で sysctl fs.inotify.max_user_watches を必ず確認するようにしてください。コンテナ集約環境では引き上げられたデフォルト値でも不足する場合があるため、現行の消費量を継続的に計測する仕組みを用意することが重要です。
切り戻し手順と監視の組み込み
sysctl のチューニングは基本的にリスクの低い変更ですが、上限値を際限なく引き上げることはカーネルリソースの浪費につながります。段階的に設定し、切り戻し手順を事前に確認しておくことが運用上の安心材料になります。
ランタイム変更は即座に切り戻せます。
# ランタイム変更の即時切り戻し(再起動不要)
sudo sysctl fs.inotify.max_user_watches=65536
sudo sysctl fs.inotify.max_user_instances=128
永続化した場合は /etc/sysctl.d/99-inotify.conf を削除またはコメントアウトし、再度 sudo sysctl --system を実行すれば元の値に戻ります。systemd を使った環境では systemd-sysctl.service が起動時に sysctl.d を適用するため、ファイルを削除すれば次回起動後にデフォルト値に戻ることも確認しておくとよいです。
再発防止には継続的な監視が不可欠です。Prometheus + node_exporter を使用している環境では、テキストコレクター(--collector.textfile)を活用して、先述の診断スクリプトをシェルスクリプトで定期実行し、プロセスごとの watch 数を Prometheus 形式で出力する構成が実用的です(以下は想定例です)。
# 想定例:テキストコレクター向けのメトリクス出力スクリプト(毎分 cron で実行)
#!/bin/bash
# /etc/node-exporter/textfile-collector/inotify.sh
total=0
for pid in $(find /proc -maxdepth 1 -name '[0-9]*' -printf '%f\n' 2>/dev/null); do
count=$(grep -c '^wd:' /proc/"$pid"/fdinfo/* 2>/dev/null || echo 0)
total=$((total + count))
done
cat < /var/lib/node_exporter/textfile_collector/inotify.prom
# HELP node_inotify_watches_total Total inotify watches in use system-wide
# TYPE node_inotify_watches_total gauge
node_inotify_watches_total $total
EOF
上限の 80% を超えたらアラートを発報する閾値設計にしておくと、枯渇する前に対処できます。inotify 枯渇は「なぜかファイル変更が検知されない」という形で静かに発現し、原因特定に時間がかかりやすい障害類型です。診断コマンドをインシデント対応手順書に組み込んでおき、上限値の設計と監視を一体で整備することが、本番環境での安定稼働につながります。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
PR・広告
コマンド操作から基本運用までを手を動かして学べる定番書。記事で触れた技術の土台固めに。
※ Amazonのアソシエイトとして、当サイトは適格販売により収入を得ています。
