目次
「df -hでは容量が40%しか使われていないのに、No space left on deviceで書き込めない」。この現象に初めて出会うと、ディスクが壊れたのかと不安になります。しかし多くの場合、原因はファイルシステムのinodeという管理領域が尽きたことで、仕組みを知っていれば数分で特定できます。
この記事では、ファイルシステムがディスク上で何をしているのかという役割から、障害時にデータを守るジャーナリング、ext4・XFS・Btrfs・ZFSの特徴と選び方、inodeの概念とdf -iでの確認、inode枯渇の対処、そして/etc/fstabとマウントオプションの実務的な書き方までを解説します。df・du・mountの基本操作はLinuxのディスク管理入門で扱っているので、本記事では「その裏側で何が起きているか」に焦点を当てます。
ファイルシステムの役割とジャーナリング
ディスクは「バイトの列」でしかない
ディスク(HDD・SSD・クラウドのブロックストレージ)は、OSから見ると単なる巨大なバイトの並びです。「ファイル名」「ディレクトリ」「更新日時」「所有者」といった概念はディスク自体にはなく、これらを管理する仕組みがファイルシステムです。どのブロックがどのファイルのものか、空いているブロックはどこか、ディレクトリの中に何があるかを記録する台帳を持ち、アプリからのopen・read・writeをブロックの読み書きに変換します。
ジャーナリングが守るもの
ファイルを1つ書くだけでも、データブロックの書き込み、inodeの更新、ディレクトリエントリの追加、空きブロック管理の更新と複数の操作が必要です。この途中で電源が落ちると、台帳とデータが食い違った状態になります。ジャーナリングは、実際の書き込みの前に「これからこういう変更をする」という記録(ジャーナル)を先に書いておく仕組みで、再起動時にジャーナルを読めば途中まで進んだ操作をやり直すか取り消すかを判断でき、台帳の整合性を短時間で回復できます。ext4の既定であるdata=orderedモードでは、メタデータの整合性は保証されますがデータ内容の完全性までは保証されない、という点は覚えておいてください。DBのようにデータ自体の整合性が必要なものは、アプリ側でfsyncを使って対処しています。
ext4・XFS・Btrfs・ZFSの特徴と選び方
4つの比較
| 項目 | ext4 | XFS | Btrfs | ZFS |
|---|---|---|---|---|
| 既定採用 | Ubuntu / Debian | RHEL / Rocky / AlmaLinux | openSUSE、Fedora(デスクトップ) | Ubuntu(オプション)、TrueNAS |
| 設計 | 伝統的なジャーナリングFS | 大容量・並列I/Oに強いジャーナリングFS | コピーオンライト(CoW) | コピーオンライト+ボリューム管理統合 |
| 縮小 | 可能(アンマウント時) | 不可(拡張のみ) | 可能(オンライン) | プールの縮小は原則不可 |
| inode | 作成時に個数が固定 | 動的に確保 | 動的 | 動的 |
| スナップショット・チェックサム | なし(LVMで代替) | なし(LVMで代替) | あり | あり |
| 向く用途 | 汎用サーバー、小〜中規模 | 大容量、DB、ログ集約 | スナップショット重視の運用 | NAS、大規模ストレージ |
実務での判断
一般的なWebサーバーやアプリサーバーであれば、ディストリビューションの既定に従うのが最も安全です。ext4は枯れていて情報が豊富で、縮小もできるため小規模環境で扱いやすい選択です。XFSは大きなファイルや多数の並列書き込みに強く、RHEL系では標準なので、DBやログ集約サーバーでは自然な選択になります。ただし「縮小できない」ことは意識しておく必要があります。
BtrfsとZFSはコピーオンライト(既存ブロックを上書きせず、新しいブロックに書いて参照を切り替える方式)を採用しており、瞬時のスナップショット、データのチェックサムによる破損検知、透過的な圧縮といった機能を持ちます。バックアップ前にスナップショットを取り、整合性の取れた状態からコピーするといった運用が組みやすい一方、CoW特有の断片化や、DBのような頻繁な上書き用途では性能面の考慮が必要です。ZFSはライセンス上Linuxカーネル本体には含まれず、別途モジュールとして導入します。rsyncやtarによるバックアップで十分な小規模環境では、まずext4/XFSで始めて問題ありません。
inodeとは何か
ファイルの「身分証明書」
inodeは、ファイル1つにつき1つ割り当てられる管理情報の入れ物です。所有者、パーミッション、サイズ、更新日時、そして「データがどのブロックにあるか」を記録しています。ファイル名はinodeには含まれず、ディレクトリが「名前→inode番号」の対応表を持っています。ls -iでinode番号を見ることができ、ハードリンクが「同じinodeを指す別の名前」であることもこの構造から理解できます。
# inode番号とファイル情報を確認
ls -li /var/log/syslog
stat /var/log/syslog
# ファイルシステムごとのinode使用状況
df -i
# Filesystem Inodes IUsed IFree IUse% Mounted on
# /dev/nvme0n1p1 3276800 3276800 0 100% /
ext4はinodeの数が作成時に決まる
ここが重要なポイントで、ext4ではmkfsの時点でinodeの総数が固定されます。既定では「16KBあたり1個」の割合で確保されるため、平均ファイルサイズが16KBを大きく下回るような環境(大量の小さなキャッシュファイル、セッションファイル、メール、node_modules)では、容量より先にinodeが尽きます。後から増やすことはできず、対処は再フォーマットしかありません。XFSやBtrfsは必要に応じて動的に確保するため、この問題は実質的に起きません。
トラブル事例:容量は残っているのに書き込めない
症状:PHPで動くECサイトで、注文確定時にfailed to open stream: No space left on deviceが発生。df -hではルートパーティションの使用率は42%。
原因:df -iを実行するとIUse%が100%だった。原因を探すと、セッションのガベージコレクションが動いておらず、/var/lib/php/sessionsに数百万個の小さなセッションファイルが溜まっていた。1ファイルは数百バイトなので容量は消費しないが、inodeは1ファイルにつき1つ消費するため先に枯渇していた。
対処:まず古いセッションファイルを削除して復旧し、PHPのsession.gc_probabilityとcronによる定期削除を設定。inode枯渇の犯人を探すコマンドは次のとおりです。
# ディレクトリごとのファイル数を集計し、多い順に表示
sudo find / -xdev -printf '%h\n' | sort | uniq -c | sort -rn | head -n 20
# 特定ディレクトリの古いファイルを削除(例:30日以上前のセッション)
sudo find /var/lib/php/sessions -type f -mtime +30 -delete
# 削除後に確認
df -i /
削除してもdfの値が減らない場合は、削除済みファイルをプロセスがまだ開いている状態なので、lsof +L1で該当プロセスを探して再起動します。なお、大量の小ファイルを扱うことが最初からわかっている場合は、mkfs.ext4 -T newsや-i 4096のようにinode密度を上げて作成するか、XFSを選ぶのが根本対策です。
fstabとマウントオプションの実務
fstabの書き方とUUID
/etc/fstabは起動時に自動マウントするファイルシステムの一覧で、「デバイス・マウント先・種類・オプション・dump・fsck順」の6項目で構成されます。デバイス名(/dev/sdb1など)は接続順で変わることがあるため、blkidで確認したUUIDで指定するのが鉄則です。fstabの記述ミスは起動失敗に直結するので、書いた後は必ずmount -aで検証してから再起動してください。
# UUIDを確認
sudo blkid /dev/nvme1n1
# /etc/fstab の例(データ用ディスクをXFSでマウント)
UUID=3f2a...-... /data xfs defaults,noatime,nofail 0 2
# 再起動せずに検証(エラーが出なければOK)
sudo mount -a
findmnt /data
押さえておきたいオプション
- noatime / relatime:ファイルを読むたびにアクセス時刻を書き込むのを抑制します。現在の既定はrelatimeで、多くのサーバーはこれで十分ですが、読み取りが極端に多い用途ではnoatimeにする余地があります
- nofail:そのディスクが見つからなくても起動を続行します。クラウドで後から追加したデータディスクには必ず付けておくと、ディスクの付け外しで起動不能になる事故を防げます
- discard:SSDにTRIMを即時通知します。ただし性能面から、マウントオプションではなく
fstrim.timerによる定期実行が推奨されるのが一般的です - errors=remount-ro(ext4):エラー検出時に読み取り専用で再マウントし、被害の拡大を防ぎます。ルートパーティションでは既定で有効です
クラウドでディスクを拡張した場合は、パーティションを広げたうえで、ext4ならresize2fs、XFSならxfs_growfsをマウントしたまま実行できます。EC2の運用ではEBSの拡張後にこの手順が必要になります。複数ディスクの束ね方やボリューム管理はRAIDとLVM入門で扱います。
まとめ
ファイルシステムは、バイトの列でしかないディスクに「ファイル」という概念を与える台帳であり、ジャーナリングによって障害時の整合性を守っています。ext4とXFSはサーバー用途の定番で、ディストリビューションの既定に従いつつ、XFSは縮小できない点、ext4はinode数が固定される点を意識して選びます。BtrfsとZFSはスナップショットとチェックサムが必要な運用で検討します。「容量が残っているのに書けない」ときはdf -iを最初に確認し、小ファイルの溜まり場をfindで特定してください。fstabはUUIDで書き、データディスクにはnofailを付け、mount -aで検証する。この習慣だけでストレージ起因の障害はかなり減らせます。
サーバーのストレージ設計や既存環境の見直しでお困りの際は、Harmonic Societyのシステム開発・インフラ支援にご相談ください。
Harmonic Society
この記事の内容、自社の業務でも活かせそうですか?
ローカルLLM・AI・クラウドなどの技術導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK。まずは30分の無料相談から。売り込みはしません。
関連記事
Related / 9 articles
Notes & Insights
- プログラミング
DDoS攻撃の仕組みと対策入門|レイヤー別の防御とCDN・クラウドの活用
DDoS攻撃をボリューム型・プロトコル型・アプリ層に分けて仕組みを解説し、自前サーバーで防げない理由、CloudflareやAWS Shieldの標準防御、オリジンIPの隠し方、レートリミットとBot対策、攻撃を受けたときの初動、費用が跳ね上がるDenial of Walletへの備えまでわかります。
- プログラミング
WAFとは?仕組み・導入パターン・誤検知対策|Webアプリを攻撃から守る実践ガイド
WAFがファイアウォールやIDSと何が違うのか、シグネチャとマネージドルールの仕組み、Cloudflare WAF・AWS WAF・ModSecurityの比較、フォーム送信がブロックされる誤検知の調査と例外設定、ログ監視、WAFが代替できないことまで実践的に解説します。
- プログラミング
セキュリティヘッダー入門|CSP・HSTS・X-Frame-Optionsの設定と効果を実践解説
CSP・HSTS・X-Frame-Options・X-Content-Type-Optionsなど主要セキュリティヘッダーが防ぐ攻撃と、CSPのReport-Onlyからの段階導入、nonce/hash、HSTS preloadの不可逆リスク、Nginx・Next.js・Astroでの設定例、確認方法を解説します。
- プログラミング
クラウドの通信費(Egress)入門|データ転送量課金の仕組みと転送コストを抑える設計
クラウドの「受信無料・送信有料」の原則、AZ間・リージョン間・インターネット向けの単価差、NATゲートウェイ処理料の罠、CDNで転送量を減らす方法、バックアップやログ転送の見落とし、請求書で転送料を特定する手順を解説。想定外の請求を防げます。
- プログラミング
秘密情報をGitに入れない仕組み|.gitignore・git-secrets・履歴から漏れた鍵の削除
APIキーや.envをGitにコミットしてしまう典型経路と、.gitignore・.env.exampleの運用、pre-commitでのgitleaks検知、GitHub secret scanningの活用、漏れた鍵の無効化と履歴書き換え(git filter-repo)の手順を解説。仕組みで再発を防げます。
- プログラミング
開発・ステージング・本番環境の分離設計|環境差分をなくす構成とアクセス制御
開発・ステージング・本番それぞれの目的と、構成をコードで揃える方法、環境別の設定注入、本番データを使わないテストデータ戦略、ステージングの保護(Basic認証・IP制限・noindex)、コストを抑える運用までを解説。環境差分による本番障害を防げます。
- プログラミング
ngrok・Cloudflare Tunnelでローカルを公開|Webhook開発とデモ環境の作り方
NAT内のローカル環境にStripeやLINEのWebhookを届けるトンネリングの仕組みを解説。ngrok・Cloudflare Tunnel・localtunnelの比較、固定ドメインと認証、リクエスト検査、公開時のセキュリティ、自宅サーバー公開への応用までわかります。
- プログラミング
ローカル開発環境のHTTPS化|mkcert・hostsファイル・自己署名証明書の正しい使い方
ローカル開発をHTTPS前提にすべき理由(Secure Cookie・Service Worker・OAuth)と、mkcertでローカルCAを作りhostsで独自ドメインを割り当ててVite・Next.js・Dockerで使う手順を解説。証明書警告を無視する癖の危険も理解できます。
- プログラミング
localhost・0.0.0.0・127.0.0.1の違い|ポートとUnixソケットを理解して「つながらない」を解決
localhost・127.0.0.1・0.0.0.0の意味の違い、Dockerで外から接続できない原因、host.docker.internal、ポート競合の調べ方、Unixソケットの利点と権限、1024未満ポートの制約を解説。「つながらない」を仕組みから解決できます。
Harmonic Society
「読んで終わり」にせず、自社の業務で試してみませんか?
AI・ローカルLLM・クラウドの導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK・売り込みなし。
無料・30分・オンラインOK|1営業日以内に返信します