AWS DevOps Agent と EC2 障害調査をやってみた 〜inode 枯渇編〜

AWS DevOps Agent と EC2 障害調査をやってみた 〜inode 枯渇編〜

千葉です。ディスク使用率に余裕があるのに「No space left on device」エラーが出る謎のトラブル。AWS DevOps Agentとペアオペレーションで、本番環境でもよくある「inode枯渇」の調査から復旧まで、実践的なトラブルシューティングをお見せします。
2026.05.22

コンニチハ、千葉です。

突然ですが、こんな経験はありませんか?

「ディスク使用率 80% で余裕あるのに、なぜかファイルが書けない……?」

今回は AWS DevOps Agent を使ってEC2の障害調査をやってみました。
テーマは本番でもたまに遭遇する inode 枯渇 です。

df -h ではディスクに余裕があるのに No space left on device が出る、トラップです。罠です。
DevOps Agent は AWSクラウド側の情報は調べられますが、EC2 の OS 内部でコマンドを実行する機能は持っていません
なので「AIが状況を分析・指示して、人間が手を動かす」というペアオペレーションで進めていきます。

検証環境の構築

前提条件

  • AWS DevOps Agent が有効化済み

EC2 の起動

Amazon Linux 2023 の EC2 を起動します。インスタンスタイプは t3.small 程度で十分です。
ストレージはデフォルトの 8GB のままにしてください(inode 総数が少なく、枯渇させやすいため)。

nginx + PHP-FPM のインストール

EC2にログインし、以下を実行します。

# パッケージインストール
sudo dnf install -y nginx php-fpm

# nginx 設定
sudo tee /etc/nginx/conf.d/app.conf << 'EOF'
server {
    listen 80;
    root /var/www/html;
    index index.php;

    location /health {
        return 200 "ok";
        add_header Content-Type text/plain;
    }

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        root /var/www/html;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}
EOF

# テスト用 PHP ファイルの配置
sudo mkdir -p /var/www/html
sudo tee /var/www/html/index.php << 'EOF'
<?php
$result = session_start();
if ($result === false) {
    http_response_code(500);
    echo "session error";
    exit;
}
$_SESSION['ts'] = time();
echo "session id: " . session_id();
EOF

# パーミッション設定
sudo chown -R nginx:nginx /var/www/html
sudo chmod 755 /var/www/html
sudo chmod 644 /var/www/html/index.php

# PHP-FPM の実行ユーザーを nginx に変更
sudo sed -i 's/^user = .*/user = nginx/' /etc/php-fpm.d/www.conf
sudo sed -i 's/^group = .*/group = nginx/' /etc/php-fpm.d/www.conf

# セッション保存ディレクトリの権限設定
sudo chown -R nginx:nginx /var/lib/php/session
sudo chmod 700 /var/lib/php/session

# サービス起動
sudo systemctl enable --now nginx php-fpm

ALB の作成

  1. ALB を作成(Internet-facing、HTTP:80)
  2. ターゲットグループを作成
    • ターゲットタイプ: インスタンス
    • プロトコル: HTTP / ポート: 80
    • ヘルスチェックパス: /index.php
  3. EC2 をターゲットグループに登録

ALB の DNS 名にブラウザでアクセスしてセッションIDが表示されれば OK です。

擬似障害の仕込み(inode 枯渇の再現)

/var/lib/php/session ディレクトリに inode を制限した仮想ディスクを作成してマウントします。

# 2. inode 数を制限した仮想ディスクを作成
sudo dd if=/dev/zero of=/tmp/sessionfs.img bs=1M count=100
sudo mkfs.ext4 -N 50000 /tmp/sessionfs.img

# 3. /var/lib/php/session にマウント
sudo mount -o loop /tmp/sessionfs.img /var/lib/php/session
sudo chown nginx:nginx /var/lib/php/session

# 4. マウント確認(Inodes が 50000 程度になっていれば OK)
df -i /var/lib/php/session

環境ができました。早速障害を発生させてみましょう。
以下のスクリプトで /var/lib/php/sessions/ に大量のセッションファイルを生成して枯渇させます。

sudo python3 << 'EOF'
import os, random, string, sys

base = '/var/lib/php/session/'
chars = string.ascii_lowercase + string.digits
target = 510000  # inode 総数の約 98% を目標に

print(f"Creating {target:,} session files...")
for i in range(target):
    fname = ''.join(random.choices(chars, k=26))
    open(f'{base}sess_{fname}', 'w').close()
    if i % 50000 == 0:
        print(f"  {i:,} / {target:,} ...")

print("Done! Check with: df -i")
EOF

完了後、inode の使用状況を確認します。

df -i /var/lib/php/session
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/loop0      50024 50024     0  100% /var/lib/php/session

100% に達したら準備完了です。
PHP セッション書き込みが失敗し始め、ALB のヘルスチェックが失敗するまでしばらく待ちます(ALB のヘルスチェック間隔によりますが、1〜2 分程度です)。

Step 1: DevOps Agent に調査を依頼

インシデントレスポンス から 調査を開始に以下を入力して実行しました。

ALB にて 5xx エラーが急増しています。
ターゲットグループ web-tg でインスタンス i-xxxUnhealthy と判定されています。
EC2 インスタンスのステータスチェックは正常(2/2 passed)です。
次のステップ: インスタンスにログインして Web サーバーとアプリケーションの状態を確認してください。

調査が開始されました。CloudWatchからCPUやメモリの情報、リソースの作成したタイミングなど、いつ何が起きてるか、関連性が調査されていきます。

調査のサマリです

  • EC2がターゲットグループに登録された時間を把握 → 私の操作内容が全部ばれているw
  • CPU使用率に問題ないか調査 → 問題なし
  • メモリ使用率に問題ないか調査 → 問題なし
  • EBSディスクI/Oに問題ないか調査 → 問題なし
  • ネットワークトラフィックに問題がないか調査 → 問題なし
  • EC2ステータスチェックに問題がないか調査 → 問題なし
  • アプリケーションログの調査 → CloudWatch Logs にデータがないので調査不能
  • SSM を使用してインスタンスに直接アクセスし、ログを確認するタスクを作成 → 設定していないので調査不能

様々な観点の調査の結果、以下の仮説が提示されましたが、アプリケーションのログが取得できてないので仮設止まりでした。

仮説

  • /index.php ファイルが存在しないか、PHP 実行環境に問題がある → 私が直掩に操作した内容ですが、直接原因ではありません。ログが少ない状況のため、仮説に留まってます。

調査ギャップ

  • CloudWatch Logs によるアプリケーションログ分析が不可能
  • SSM Run Command によるインスタンスログの直接アクセスが制限

とあります。これは、その通りです。SSM Run Command については、そもそも DevOps Agent による利用が AWS側で制限されているようです。

Step 2: チャットで追加調査を依頼する

インシデントレスポンスでは、調査に対して現在チャットでやり取りができないようです。そのため、新しいチャットより以下のメッセージを送りました

調査 2026-05-22T09:25:56.764Z の調査結果では、OSにログインできなので調査が難しいとありました。コマンドを提示してください。OSでコマンドを実行します。ログの情報を元に原因を追求してください。

すると、コマンドの提案があったので、実行してログをチャットに送ってみます。

1️⃣ Webサーバーの状態確認

# Apache の場合
sudo systemctl status httpd

# Nginx の場合
sudo systemctl status nginx

2️⃣ PHP-FPM プロセスの確認

sudo systemctl status php-fpm
3️⃣ index.php ファイルの存在確認

# ファイルが存在するか、パーミッションは適切か
sudo ls -la /var/www/html/index.php

# ドキュメントルートの確認(Apache)
grep DocumentRoot /etc/httpd/conf/httpd.conf
4️⃣ Webサーバーのエラーログ確認

# Apache の場合
sudo tail -n 100 /var/log/httpd/error_log

# Nginx の場合
sudo tail -n 100 /var/log/nginx/error.log
5️⃣ PHPエラーログの確認

sudo tail -n 100 /var/log/php-fpm/error.log
# または
sudo tail -n 100 /var/log/php-fpm/www-error.log
6️⃣ アクセスログで500エラーの詳細確認

# Apache の場合
sudo grep "index.php" /var/log/httpd/access_log | grep " 500 "

# Nginx の場合
sudo grep "index.php" /var/log/nginx/access.log | grep " 500 "
7️⃣ ディスク容量の確認
df -h

ログを送ったところ...

完璧です!原因が特定できました! と回答あり、おっ!と思いましたが、ディスク容量ないよとありました。

nginxのログから以下を拾ったようです。
No space left on device (28) in /var/www/html/index.php on line 2

しかし、まだ容量はあります。別の原因の可能性がないか突っ込みました。

すると!!!!

これはinode枯渇の可能性が高いです。ディスク容量は残っていても、ファイル数が上限に達している場合があります。
追加の診断コマンドを実行してください
df -i
ls -la /var/lib/php/session | wc -l
find /var/lib/php/session -type f | wc -l

ついに、原因に近づきました。コマンドを取得してログを送りました。

完璧です!原因が特定できました!
真の根本原因: inode枯渇

ようやく特定しました。かなり調査能力が高いですね。
合わせて、解決方法を提示してくれました。

恒久対応も提示あります。

以下のコマンドを実行してください:

1️⃣ 古いセッションファイルを削除

# 全セッションファイルを削除(アクティブセッションがない前提)
sudo find /var/lib/php/session -type f -delete

# 実行後、inode使用状況を確認
df -i /var/lib/php/session
2️⃣ PHP-FPM と Nginx を再起動

sudo systemctl restart php-fpm
sudo systemctl restart nginx
3️⃣ 動作確認

# index.phpへアクセスしてエラーがないか確認
curl -I http://localhost/index.php
🛡️ 恒久的な対策
オプションA: PHPセッションガベージコレクションの有効化

# セッション自動削除の設定を確認
sudo grep -E "session.gc" /etc/php.ini

# 以下の設定を追加・修正(viまたはsedで編集)
sudo vi /etc/php.ini
以下を設定:

session.gc_probability = 1
session.gc_divisor = 100
session.gc_maxlifetime = 1440  # 24分(1440秒)

オプションB: cronで定期的にセッションファイルを削除

# cronジョブを追加(10分ごとに古いセッションを削除)
sudo crontab -e
以下を追加:

*/10 * * * * find /var/lib/php/session -type f -mmin +30 -delete

無事復旧できました!!!

調査ステップのまとめ

ステップ 担当 やったこと 判明したこと
1 DevOps Agent CloudWatch・EC2ステータス確認 ALB が Unhealthy、EC2 は起動中
2 DevOps Agent ログが確認できず仮説止まり AWS側で見えるリソースやログ状は問題がないこと
3 DevOps Agent+人間 インシデントレスポンスの調査結果をベースにコマンドを提示してもらいEC2の中のログを取得提示 ディスク容量枯渇にたどり着いた
4 DevOps Agent + 人間 容量あるとツッコミをいれ、inodeかもと応答ありコマンドの提示あり inode 100% 枯渇を発見
5 DevOps Agent + 人間 問題ディレクトリ特定・削除・復旧確認・恒久対応 暫定のみならず恒久対応が提示された

最後に

inode 枯渇、地味にあるあるですよね!

千葉的に今回一番刺さったのは Step 3 で df -h に騙されるところ です。人間と同じくちゃんと騙されました。
ディスクに空きがあるのに書けない。一言ツッコミ「ディスク容量はまだあるので他に原因がないか」で、すぐに inode かもと次の調査コマンドをもらえました。

EC2 の内部まで入れないという制約はありつつも、「次に何をすべきか」を整理してもらえるのは深夜のインシデント対応ではかなり心強いです。

また、DevOps Agent が一度調査した内容も知識として会話することができるので、前提の認識合わせがかなり楽でした。一から説明しなくても良いのです。

なお今回の教訓として、DevOps Agentとはイミュータブルを守るためEC2へコマンド実行ができません。確実に原因に辿り着くにはOSやアプリのログ含め事前にできる限り CloudWatch に保存しておく必要があります。
逆にログさえあれば、高い精度で問題に辿り着くことができることを確認できました。

それではまた!

この記事をシェアする

関連記事