サーバー停止の恐怖から解放!「ディスク容量監視」と「ログ自動整理」の完全自動化

【実践シェルスクリプト講座 第1回】サーバーが止まるその前に…。「監視」と「掃除」を自動化して安眠を手に入れよう

こんにちは!「リナックス先生」です。
今回から全5回にわたり、現場で本当に役立つ「実践シェルスクリプト講座」を開講します。
教科書的なコマンドの説明ではなく、「実際に起きるトラブル」を解決するための自動化ツールを、一緒に作り上げていきましょう。

コウ君、最近サーバーの管理はどう?手動で毎日チェックしてる?

コウ君

先生!それが…実は昨日、テストサーバーが突然動かなくなって焦りました。
原因を調べたら、ログファイルが肥大化してディスクがパンパンになっていて…。
「No space left on device」ってエラーが出て、SSHすら繋がりませんでした(泣)。

リナックス先生

典型的な「ディスクフル障害」ね。
サーバーエンジニアが最初に経験する洗礼のようなものよ。
でも、人間が毎日 df コマンドを打って監視するのはナンセンス。そんな単純作業こそ、スクリプトに任せるべきよ!

記念すべき第1回は、サーバー運用の基本中の基本である「ディスク容量の監視」と、その原因となる「ログファイルの自動ローテーション(掃除)」を行うスクリプトを作成します。
最初からプロの現場で通用する「エラー処理(安全性)」を意識したコードを書いていきますよ。

本講座のカリキュラム(全5回)

本シリーズでは、以下のステップで「最強の自動化サーバー」を構築します。

  1. 【今回】サーバー停止の恐怖から解放!「ディスク容量監視」と「ログ自動整理」の完全自動化
  2. データ消失をゼロにする!「堅牢バックアップ」と「Slack通知」の構築
  3. 手作業を撲滅せよ!「ユーザー一括作成」と「SSH鍵配布」の自動化スクリプト
  4. 攻撃者を秒でブロック!ログ解析による「SSH総当たり攻撃」自動防御システム
  5. プロの品質へ!スクリプトの「安全性向上(デバッグ)」と「トラブルシューティング」

1. そもそも、なぜ「監視」と「ローテーション」が必要なのか?

サーバーは24時間365日動き続け、常に何らかのデータを書き込んでいます。
特に「ログファイル」は、放っておくと数GB、数TBへと成長し、物理的なディスク容量を食いつぶします。

💡 ディスクがいっぱいになると起こる悲劇

  • データの喪失: 新しいデータベースの書き込みができず、データが消える。
  • サービスの停止: Webサーバーがセッションファイルを作れず、サイトが閲覧不能になる。
  • システムダウン: OS自体が一時ファイルを作れず、コマンド操作すら受け付けなくなる。

こうなってから対応するのでは遅いのです。
「危なくなる前に通知する」仕組みと、「定期的にゴミを片付ける」仕組みの2つが不可欠です。

2. ディスク使用率監視スクリプトを作る

まずは、現在のディスク使用量をチェックし、設定した閾値(いきち)を超えていたら警告を出す disk_alert.sh を作成します。

Step 1: コマンドで数値を取り出す

まずは手動でコマンドを組み立ててみましょう。
df -h コマンドは見やすいですが、スクリプト処理には向きません。単純な df を使い、テキスト処理ツール awksed で「使用率(%)」の数字だけを抜き出します。

[root@localhost ~]# df / | tail -1 | awk '{print $5}' | sed 's/%//'
84

この「84」という数字が取れれば、あとは if 文で比較するだけですね。

Step 2: 安全なスクリプトを書く(disk_alert.sh)

vim disk_alert.sh を作成します。
今回は最初から「変数の未定義エラー」などを防ぐ安全策(set -u)を入れておきます。

#!/bin/bash

# --- 安全設定 ---
# set -u : 未定義の変数を使おうとしたらエラーで停止する(誤動作防止)
set -u

# ==========================================
# 設定エリア
# ==========================================
# 監視対象のマウントポイント
TARGET="/"
# 警告を出す閾値(パーセント)
THRESHOLD=80
# ログファイル(cron実行時の確認用)
LOG_FILE="/var/log/disk_alert.log"

# ==========================================
# メイン処理
# ==========================================

# ログ出力用関数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# ディスク使用率を取得
# 実行結果を変数に入れるときは $(...) を使う
current_usage=$(df "$TARGET" | tail -1 | awk '{print $5}' | sed 's/%//')

# 数値チェック(空だったり数字以外だった場合の安全策)
if ! [[ "$current_usage" =~ ^[0-9]+$ ]]; then
    log "【ERROR】ディスク使用率の取得に失敗しました。"
    exit 1
fi

# 閾値と比較
# -ge : Greater than or Equal (以上)
if [ "$current_usage" -ge "$THRESHOLD" ]; then
    log "【DANGER】ディスク容量が危険水準です! 使用率: ${current_usage}% (閾値: ${THRESHOLD}%)"
    
    # ★ここにメール送信やSlack通知のコマンドを追記可能
    # echo "Disk Alert" | mail -s "Warning" admin@example.com
else
    log "【OK】ディスク容量は正常です。 使用率: ${current_usage}%"
fi

Step 3: 動作確認

実行権限を与えて動かしてみましょう。

[root@localhost ~]# chmod +x disk_alert.sh
[root@localhost ~]# ./disk_alert.sh
[root@localhost ~]# cat /var/log/disk_alert.log
[2024-01-25 10:00:00] 【OK】ディスク容量は正常です。 使用率: 45%

これで、1時間に1回このスクリプトを動かせば、気づかぬうちに100%になる事故は防げます。

3. ログローテーションスクリプトを作る

監視ができたら、次は「掃除」です。
Linuxには logrotate という標準機能がありますが、自作アプリのログや、特定の一時ファイルを柔軟に管理したい場合、シェルスクリプトで書けると非常に強力な武器になります。

仕様を決定する

今回は以下の要件で log_rotate.sh を作成します。

  1. 対象:/var/log/myapp/app.log
  2. 処理:現在のログを app.log.YYYYMMDD にリネームして退避。
  3. 再生成:空の app.log を新しく作る。
  4. 圧縮:退避したログを gzip で圧縮する。
  5. 削除:30日以上経過した古い圧縮ログを削除する。

スクリプトの実装(log_rotate.sh)

ここでも、現場で必須の「エラーハンドリング(set -e)」を導入します。

#!/bin/bash

# --- 安全設定 ---
# set -e : コマンドが1つでも失敗したらスクリプトを即座に停止する
# set -u : 未定義変数エラーチェック
set -eu

# ==========================================
# 設定エリア
# ==========================================
LOG_DIR="/var/log/myapp"
LOG_FILE="app.log"
RETENTION_DAYS=30
TODAY=$(date +%Y%m%d)

# ==========================================
# メイン処理
# ==========================================

# ディレクトリへ移動
# もしディレクトリ変数が間違っていても、set -uで検知できる
# 移動に失敗したら set -e で止まるので、誤爆を防げる
cd "$LOG_DIR"

# 対象ログファイルがなければ終了(正常終了とする)
if [ ! -f "$LOG_FILE" ]; then
    echo "対象ファイル($LOG_FILE)がないためスキップします。"
    exit 0
fi

echo "--- ローテーション開始: $TODAY ---"

# 1. リネーム(退避)
mv "$LOG_FILE" "${LOG_FILE}.${TODAY}"
echo "退避完了: ${LOG_FILE}.${TODAY}"

# 2. 空ファイル再作成
touch "$LOG_FILE"
chmod 644 "$LOG_FILE"
echo "新規作成完了: $LOG_FILE"

# 3. 圧縮
gzip "${LOG_FILE}.${TODAY}"
echo "圧縮完了: ${LOG_FILE}.${TODAY}.gz"

# 4. 古いログの削除
# find -mtime +30 : 30日より前のファイルを検索
echo "保存期間(${RETENTION_DAYS}日)経過ログを削除中..."
find . -name "${LOG_FILE}.*.gz" -mtime +$RETENTION_DAYS -delete -print

echo "--- 処理完了 ---"
コウ君

先生、set -e ってそんなに大事なんですか?
書いてなくても動きますよね?

リナックス先生

いい質問ね。
例えば、ディスクがいっぱいで mv (リネーム) に失敗したとしましょう。
set -e がないと、スクリプトはそのまま次の行に進んで、まだ移動できていないログファイルに touch で上書きしたり、中途半端な状態で圧縮を始めたりして、ログが消失する大事故になるの。
「失敗したらすぐに止まる」のは、システムを守るための鉄則よ!

4. Cronによる定期実行の設定

最後に、これらをCronに登録して完全自動化します。
ここで初心者が最もハマる罠が「環境変数PATH」です。

Cronの鉄則

Cronで動くときは、ターミナルで操作している時とは違い、最小限のコマンドしかパスが通っていません。
そのため、スクリプト内で gzipdf が「command not found」になることがあります。
これを防ぐには、スクリプトの先頭でPATHを定義するか、Cron側で定義します。

今回は、crontab -e で編集する際にPATHを指定する方法を紹介します。

# 環境変数を定義(これ以下の行に適用される)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

# 毎時0分にディスク容量監視
0 * * * * /root/scripts/disk_alert.sh >> /var/log/cron_disk.log 2>&1

# 毎日AM 3:30 にログローテーション
30 3 * * * /root/scripts/log_rotate.sh >> /var/log/cron_rotate.log 2>&1

2>&1 は「エラーメッセージも一緒にログファイルに保存する」という意味です。
これを忘れると、スクリプトが動かなかった時に原因がわからなくなります。

まとめ:自動化で「時間」を作ろう

今回は第1回として、サーバー管理の基本「監視と掃除」を自動化しました。

スクリプト 役割 プロのテクニック
disk_alert.sh ディスク容量の監視 awkでの数値抽出、set -uでの変数保護
log_rotate.sh ログの掃除と圧縮 set -eでの異常時停止、find -delete

これらをセットしておけば、コウ君のように「朝起きたらサーバーが死んでいた」という悪夢を見る確率はグッと下がります。
空いた時間で、新しい技術の勉強や、サービスの改善に取り組みましょう。

次回予告:データ消失の悲劇を防ぐバックアップ術

ディスクの監視はできましたが、サーバーには「ハードウェア故障」や「操作ミスによる削除」というリスクがつきまといます。
次回は、「tarコマンドによる世代管理バックアップ」と、「rsyncによる高速同期」、そしてスクリプトが失敗した時にSlackやメールに通知を飛ばす「通知システム」を構築します。

「バックアップ取ってませんでした…」で人生を棒に振らないために、次回も必見です!

リナックス先生

今回のスクリプトを試すときは、いきなり本番環境ではなく、まずは手元の仮想環境やテスト用のVPSで試してね。
失敗して覚えることも多いけど、本番データだけは守りましょう!

▼スクリプトの実験場に最適!推奨VPS

【2026年最新】Linuxサーバー構築におすすめのVPS比較3選!現役エンジニアが速度とコスパで厳選
Linuxの勉強、まだ「自分のPC」でやって消耗していませんか?「Linuxを覚えたいけど、環境構築でエラーが出て先に進めない…」「VirtualBoxを入れたらパソコンが重くなった…」これは、Linux学習を始める9割の人がぶつかる壁です...

コメント