Shellの基礎知識(実践編)

【RHEL系Linux】ディスク使用率を自動監視するシェルスクリプトの実装

ディスクの使用率、気づいたときには手遅れになっていませんか?

サーバー運用では、容量逼迫によるサービス停止を未然に防ぐことが重要です。

この記事では、あらかじめ定義した閾値を元にディスク使用率を自動監視し、ログに記録するシェルスクリプトの仕組みを解説します。

運用自動化ツール

🟡 運用自動化ツール
📌 面倒な作業を一括効率化!シェルスクリプトで実現する運用自動化術
├─ 基本共通
| ├─【Shellの基礎知識】簡単なログ出力ロジックを作ってみました。
| ├─【Shellの基礎知識】シェルスクリプトの作成を時短!テンプレートで効率化する方法
| ├─【Shellの基礎知識】共通関数定義クラスの完全ガイド!設計から実践まで徹底解説
├─ 開発環境構築
| ├─【RHEL系Linux】開発サーバー初期設定スクリプトの完全自動化
| ├─【RHEL系Linux】Apache+Let's Encrypt 自動構築スクリプト|バーチャルホスト対応
| ├─【RHEL系Linux】Tomcatを自動インストール・設定するスクリプトの作成と活用法
| └─【RHEL系Linux】PostgreSQLを自動インストールするシェルスクリプトの使い方
└─ 運用・保守
  ├─【RHEL系Linux】任意サービスを簡単制御!汎用サービススクリプトの活用術
  ├─【RHEL系Linux】ファイルやログを自動圧縮する汎用スクリプトの実装と活用法
  ├─【RHEL系Linux】リソース(CPU・MEM)監視スクリプトで使用率・異常を検知する仕組み
  ├─【RHEL系Linux】中間ファイル連携を完全制御するファイル転送スクリプト
  ├─【RHEL系Linux】信頼性を重視した完了保証型ディレクトリ転送スクリプトの設計と実装
  ├─【RHEL系Linux】ディスク使用率を自動監視するシェルスクリプトの実装
  └─【RHEL系Linux】サーバーの障害検知と自動通知|systemdログ監視の実装例

概要と導入の目的

ディスク容量の逼迫は、サーバー障害の中でも特に予兆を見落としやすく、サービス停止に直結するリスクを持っています。特にバックアップやログ肥大などによる想定外の使用率上昇は、事前に監視しておくことが重要です。本記事では、指定した閾値に基づいてディスク使用率を自動監視し、ログ出力するシェルスクリプトの導入と活用法について解説します。

サーバー運用におけるディスク監視の重要性

ディスク監視はCPUやメモリに比べて軽視されがちですが、予兆がわかりやすくかつ致命傷になりやすい項目です。定期監視を怠ると、以下のような事態を引き起こします。

  • ログやバッチ処理による容量圧迫に気づかず障害発生
  • 一部アプリケーションがエラー停止し、業務システムが不安定に
  • クラッシュ時に証跡が保存できず、原因解析が困難

予兆のあるうちに対応できれば、業務影響は最小限に抑えられます。そのためには「一定以上の使用率を検出したら記録」「複数回の連続検出で重大度を判断する」というしくみが不可欠です。

このスクリプトの導入効果とユースケース

このスクリプトは、あらかじめ定義された設定ファイル(disk_threshold.conf)に従って、ファイルシステム単位で監視を行い、使用率が閾値を超えたときに記録と通知を行います。特に以下のような環境で効果を発揮します。

  • 複数台構成のLinuxサーバーでのディスク利用状況の一元監視
  • cronで1日数回の定期チェックを行い、ログに蓄積する運用
  • CPUやメモリと併せてリソース監視の一環として導入

また、警告レベルと致命レベルを明確に分けて判定できるため、対応の優先順位付けにも活用できます。初期設定さえ済ませれば、日々の運用はログをチェックするだけで済み、非常に省力化されます。

スクリプトの構成と仕様

このディスク監視スクリプトは、サーバーごとに定義された設定ファイルをもとに、各ファイルシステムの使用率を監視し、警告・致命レベルの超過を検知してログに出力します。ログは共通クラス(logger.shrc)に準拠して記録され、cronなどに組み込むことで無人監視が可能です。ここでは、設定ファイルや引数仕様、ディレクトリ構成について詳しく説明します。

設定ファイル(disk_threshold.conf)の役割

閾値や警告判定回数などの監視条件は、ホスト単位で分離された disk_threshold.conf に定義します。ファイルの中身はスペース区切りで、監視対象のファイルシステムごとに設定行を記述します。
以下は設定ファイルの例です。

ファイルシステム警告判定回数警告閾値(%)致命閾値(%)
/dev/vda218090
/dev/sdb127085

この設定により、使用率が警告閾値を超過した場合に記録され、一定回数以上連続で超過が記録された場合にログ通知が発生します。

スクリプトの引数仕様と使用例

本スクリプトは、 -f および -t の2つのオプション引数に対応しており、テストモード実行や任意の時刻での実行に利用できます。

オプション意味入力例
-fdfコマンドの出力を記録したファイルパス/tmp/test_df.txt
-t任意の実行時刻を指定(ログ出力用)"2025-08-03 01:00:00"

実行コマンドの例は以下のとおりです。

sh disk_alert.sh -f /tmp/test_df.txt -t "2025-08-03 01:00:00"

このように、運用中にテスト実行したい場合や、擬似的なログを生成したい場合に役立ちます。

使用ディレクトリ構成とログの保存先

このスクリプトは、RHEL系Linux上の開発環境において共通構成で運用されることを前提に設計されています。

特に重要なのは、設定ファイル disk_threshold.conf の配置ルールです。これはマシンごとに設定値が異なることを想定しており、 etc ディレクトリの下に ホスト名を単位としたサブディレクトリを掘って、その中にファイルを配置する構成になっています。

これにより、同一スクリプトで複数ホストに対応でき、環境ごとに柔軟な運用が可能になります。
以下に主要なディレクトリとファイルの配置例を示します。

パス用途
/home/bepro/projects/scripts/binスクリプト本体(disk_alert.sh)の配置先
/home/bepro/projects/scripts/etc/dev01/disk_threshold.confホスト「dev01」専用の閾値設定ファイル
/home/bepro/projects/scripts/tmp/disk_alert.dfdfコマンドの出力キャッシュファイル
/home/bepro/projects/scripts/tmp/disk_alert.rep警告発生履歴の一時記録ファイル
/home/bepro/projects/scripts/log/disk_alert.log実行ログファイル(logger.shrc準拠)

このように、ディレクトリ構成を一貫させることで、複数サーバーをまたいだ運用や管理の標準化が実現できます。特に etc/<ホスト名>/disk_threshold.conf という構造は、スクリプト側でも自動的にホストを判別して読み込む仕様となっており、非常に効率的です。

実装ロジックと処理の流れ

このスクリプトは、単に使用率を1回チェックして通知するだけではなく、「しきい値の段階的チェック」「記録履歴の保持」「通知レベルの自動判定」といった堅牢なロジックで構成されています。スクリプト本体は読みやすさと保守性を考慮し、処理の各段階がセクションで明確に分離されています。

前提となる実行環境

Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。

実行環境

BASE_DIR(任意のディレクトリ)

  • scripts
    • bin(実行スクリプト格納領域)
      • <<各種実行スクリプト>>.sh (実行ファイル)
    • com(共通スクリプト格納領域)
      • logger.shrc(共通ログ出力ファイル)
      • utils.shrc(共通関数定義ファイル)
    • etc(設定ファイル等の格納領域)
      • infraMessage.conf(メッセージ定義ファイル)
    • log(スクリプト実行ログの格納領域)
      • スクリプト名.log 
    • tmp(テンポラリ領域)
    • rep(レポート出力領域)

ディスク監視スクリプト

ディスク監視スクリプトは、指定された閾値に基づいて各パーティションの使用率を定期的にチェックし、異常があればログ出力と通知処理を行う役割を担います。設定ファイルとログ機構を分離した柔軟な設計により、テストと本番運用の両方で効果的に活用できます。

#!/bin/sh
# ------------------------------------------------------------------
# スクリプト名 :disk_alert.sh
# 概要    :ディスク使用率を監視し、しきい値超過を通知
# 説明    :
#   - ディスク設定ファイルに記載された各ファイルシステムを対象に監視
#   - 使用率が警告・致命的閾値を超えた場合に記録・ログ出力
# ------------------------------------------------------------------

# ------------------------------------------------------------------
# 初期処理:共通関数・ログ読み込み
# ------------------------------------------------------------------
. "$(dirname "$0")/../com/utils.shrc"
. "$(dirname "$0")/../com/logger.shrc"
setLANG utf-8
runAs root "$@"

# ------------------------------------------------------------------
# グローバル変数定義
# ------------------------------------------------------------------
scope="var"

readonly JOB_OK=0
readonly JOB_ER=2

host_id=$(hostname -s)
exec_time=$(date "+%Y-%m-%d %H:%M:%S")
threshold_file="${ETC_PATH}/${host_id}/disk_threshold.conf"
usage_file="${TMP_PATH}/disk_alert.df"
record_file="${TMP_PATH}/disk_alert.rep"
file_system=""  # ← loggerで使用される変数は先に空で宣言しておく

# ------------------------------------------------------------------
# 関数定義
# ------------------------------------------------------------------
scope="func"

# 終了処理:ロック解除と一時ファイル削除
terminate() {
    releaseLock
    [ -f "$usage_file" ] && rm -f "$usage_file"
}

# 使用方法表示(テストモード対応)
usage() {
    echo "Usage: $0 [-f <df_output_file>] [-t <exec_time>]"
    echo "  -f : df出力ファイルを指定(テストモード用)"
    echo "  -t : 実行日時を指定(例:\"2025-08-03 01:00:00\")"
    exit ${JOB_ER}
}

# 引数解析(getopts)
parseArgs() {
    while getopts "f:t:" opt; do
        case "$opt" in
            f) usage_file="$OPTARG" ;;
            t) exec_time="$OPTARG" ;;
            *) usage ;;
        esac
    done
}

# 閾値・記録ファイルのロード
loadThreshold() {
    [ ! -f "$threshold_file" ] && logOut "ERROR" "閾値ファイルがありません: $threshold_file" && exitLog ${JOB_ER}
    [ ! -f "$record_file" ] && touch "$record_file"
}

# df情報取得(引数が無いときのみ)
collectDiskUsage() {
    df -P | tail -n +2 > "$usage_file"
}

# ------------------------------------------------------------------
# pre-process(事前処理)
# ------------------------------------------------------------------
scope="pre"

parseArgs "$@"

# 処理日時の初期化
if [ -z "$exec_time" ]; then
    exec_time=$(date "+%Y-%m-%d %H:%M:%S")
fi

startLog
logOut "INFO" "Args: [-f $usage_file -t $exec_time]"

if acquireLock; then
    logOut "INFO" "Lock acquired"
else
    abort "Lock acquisition failed."
fi

trap "terminate" 0 1 2 3 15
loadThreshold

[ -z "$usage_file" ] && usage_file="${TMP_PATH}/disk_alert.df"
[ ! -f "$usage_file" ] && collectDiskUsage

# ------------------------------------------------------------------
# main-process(ディスクごとの処理)
# ------------------------------------------------------------------
scope="main"

grep -v '^\s*#' "$threshold_file" | while read fs warn_crit warn_thres crit_thres; do
    logOut "DEBUG" "Checking FS: $fs"

    usage_line=$(grep -w "$fs" "$usage_file")

    if [ -z "$usage_line" ]; then
        logOut "WARN" "Filesystem not found in df output: $fs"
        continue
    fi

    usage_now=$(echo "$usage_line" | awk 'NF >= 2 {print $(NF-1)}' | sed 's/%//')

    if [ -z "$usage_now" ]; then
        logOut "WARN" "Unknown filesystem: $fs"
        continue
    fi

    logOut "INFO" "Usage for $fs = ${usage_now}% / Warn=${warn_thres}% / Crit=${crit_thres}%"

    if [ "$usage_now" -ge "$warn_thres" ]; then
        echo "$fs ${usage_now}% $exec_time" >> "$record_file"
        logOut "WARN" "Usage exceeded: ${usage_now}% for $fs"
    else
        grep -vw "$fs" "$record_file" > "${record_file}.tmp" && mv "${record_file}.tmp" "$record_file"
        logOut "DEBUG" "Usage normal: $fs"
    fi

    count_exceed=$(grep -cw "$fs" "$record_file")
    logOut "INFO" "Exceed count for $fs: $count_exceed / Threshold: $warn_crit"

    if [ "$count_exceed" -ge "$warn_crit" ]; then
        # ------------------------------------------------------
        # logSystemのmessage.conf評価で必要な変数を事前にexport
        # ------------------------------------------------------
        export fs usage_now count_exceed warn_crit warn_thres crit_thres SCRIPT_NAME

        if [ "$usage_now" -ge "$crit_thres" ]; then
            logSystem "21003"  # 致命的使用率超過 → crit閾値をsrcに含める
        else
            logSystem "11003"  # 警告使用率超過 → warn閾値をsrcに含める
        fi
    fi
done

# ------------------------------------------------------------------
# post-process(終了処理)
# ------------------------------------------------------------------
scope="post"
exitLog ${JOB_OK}

閾値チェックと記録処理の流れ

処理の開始時に、指定されたしきい値設定ファイルを読み込んだ上で、現在のディスク使用率(dfコマンド)を解析します。その結果、警告または致命的なしきい値を超えていた場合、記録ファイル(repファイル)に該当のファイルシステムと使用率を追記します。

df -P | tail -n +2 > "$usage_file"

echo "$fs ${usage_now}% $exec_time" >> "$record_file"
このように、一過性のスパイクではなく、連続的な使用率上昇を検知できるようにしています。記録はファイルシステムごとに分離され、同一ファイルシステムの監視精度が向上します。

計測結果に応じたログ出力と通知処理

使用率のチェック後は、しきい値の判定に基づいてログを出力します。ログは共通ログクラス(logger.shrc)を通じて出力されるため、全スクリプトで統一されたログ形式が維持されます。

logOut "INFO" "Usage for $fs = ${usage_now}% / Warn=${warn_thres}% / Crit=${crit_thres}%"

また、使用率がしきい値未満であった場合は、以前の記録を削除して状態をリセットする仕組みも備えています。これにより、過去の記録が残り続けて誤通知を出すことを防ぎます。

grep -vw "$fs" "$record_file" > "${record_file}.tmp" && mv "${record_file}.tmp" "$record_file"

複数回の超過判定と致命判定のロジック

記録ファイル内の行数(超過回数)をカウントすることで、一定回数以上しきい値を超えていた場合に「実際に危険な状態」と判定し、通知を出すようになっています。単発の超過で即座に通知するのではなく、警告判定回数 warn_crit を超えて初めて通知する仕様です。

count_exceed=$(grep -cw "$fs" "$record_file")

if [ "$count_exceed" -ge "$warn_crit" ]; then logSystem "11003"; fi
また、現在の使用率が致命閾値(crit)を上回っている場合は、通常の警告ログではなく致命エラー通知コード("21003")として logSystem() を通じてログに記録されます。これにより、ログのレベルと緊急度が明確に分離され、他システムとの連携やアラートの自動判定にも対応できます。

if [ "$usage_now" -ge "$crit_thres" ]; then logSystem "21003"; fi

このように、「1回超えたら通知」ではなく、「連続して超えたら通知」「致命的なら即通知」という2段階構造により、より実用的で現場向きの監視が実現されています。

実行例と活用パターン

このスクリプトは実運用にもテストにも対応できる柔軟な設計となっており、目的に応じてさまざまな実行方法が可能です。ここでは、通常運用での実行例に加えて、CPU/メモリ監視スクリプトとの併用やcron登録時の注意点についても触れていきます。

通常実行とテストモードの使い分け

実運用時には、実際の dfコマンド結果に基づいて容量をチェックしますが、テスト時には任意のファイルを入力として利用することができます。
通常の実行例は以下のとおりです。

sh disk_alert.sh -t "2025-08-03 12:00:00"

テストモードでは、あらかじめ作成したfake_df.txtなどを使って動作確認ができます。

sh disk_alert.sh -f /home/bepro/projects/scripts/tmp/fake_df.txt -t "2025-08-03 12:00:00"

このオプション指定により、テスト環境でも本番と同じロジックで通知制御を検証することができます。

CPU/メモリ監視スクリプトとの併用事例

ディスク使用率だけでなく、CPU使用率やメモリ使用量といったリソースも併せて監視したい場面は多くあります。
当環境では、resource_alert.shという別スクリプトと併用することで、以下のようなリソース統合監視が可能です。

sh disk_alert.sh -t "2025-08-03 12:00:00"

sh resource_alert.sh -m cpu -t "2025-08-03 12:00:00"

sh resource_alert.sh -m mem -t "2025-08-03 12:00:00"

それぞれのスクリプトが独立してログを出力し、通知レベルも個別に制御されているため、構成の柔軟性が高く、トラブルシューティングにも有効です。

cronジョブへの組み込みと注意点

このスクリプトは自動実行を想定しており、cron登録することで定期的な監視が可能です。
たとえば、1時間ごとにディスク監視を行うには以下のように設定します。

0 * * * * /home/bepro/projects/scripts/bin/disk_alert.sh -t "$(date '+\%F \%T')"

cronジョブで運用する際には、以下のポイントに注意してください。

項目注意点
ログ出力必ずlogger.shrcに準拠し、出力ディレクトリのパーミッションに注意
時刻引数-t オプションで現在時刻を渡すことでログ整合性を確保
環境変数cronではLANGなどが継承されないためスクリプト内で強制指定

cron環境は想定外の制限が多いため、事前に手動実行で想定通りのログや通知が得られることを必ず確認してから本番組み込みするようにしてください。

よく読まれている記事

1

「私たちが日々利用しているスマートフォンやインターネット、そしてスーパーコンピュータやクラウドサービス――これらの多くがLinuxの力で動いていることをご存じですか? 無料で使えるだけでなく、高い柔軟 ...

2

Linux環境でよく目にする「Vim」という名前。サーバーにログインしたら突然Vimが開いてしまい、「どうやって入力するの?」「保存や終了ができない!」と困った経験をした人も多いのではないでしょうか。 ...

3

ネットワーク技術は現代のITインフラにおいて不可欠な要素となっています。しかし、ネットワークを深く理解するためには、その基本となる「プロトコル」と「レイヤ」の概念をしっかり把握することが重要です。 こ ...

4

この記事は、Linuxについて勉強している初心者の方向けに「Shellスクリプト」について解説します。最後まで読んで頂けましたら、Shellスクリプトはどのような役割を担っているのか?を理解出来るよう ...

5

Javaは世界中で広く使われているプログラミング言語であり、特に業務システムやWebアプリケーションの開発において欠かせない存在です。本記事では、初心者向けにJavaの基礎知識を網羅し、環境構築から基 ...

-Shellの基礎知識(実践編)