インフラエンジニアの羅針盤

インフラエンジニア1〜3年目のための技術ガイド

AlmaLinux 10 総合ガイド 第8章: ログ管理とトラブルシューティング

公開更新

AlmaLinux 10 総合ガイド
第8章: ログ管理とトラブルシューティング

【この章で学ぶこと】 ログの読み方、問題の切り分け、システム監視
【なぜ重要か】 障害対応の90%はログから始まる
【前提知識】 第7章完了、基本的なサービス管理
【所要時間】 約3.5時間

サーバー運用において、問題は必ず発生します。サービスが起動しない、ネットワークに繋がらない、ディスクが満杯になる。これらの問題に直面したとき、あなたはどこから調査を始めますか?

答えは明確です。まずログを見る。これがインフラエンジニアの基本中の基本です。

ログには「いつ」「何が」「どうなったか」が記録されています。エラーメッセージを読めば、多くの場合、問題の原因と解決策のヒントが得られます。逆に言えば、ログを見ずに原因を推測して対処しようとすると、無駄な時間を浪費することになります。

この章では、ログファイルの構成と読み方、journalctlの実践的な使い方、そして3つのケーススタディを通じてトラブルシューティングの思考プロセスを身につけます。

目次
  1. 8.1 ログファイルの基礎
    1. 8.1.1 なぜログが重要なのか
    2. 8.1.2 /var/logディレクトリの構成
    3. 8.1.3 主要なログファイル
    4. 8.1.4 ログの世代管理(logrotate)
    5. 8.1.5 ログのタイムスタンプの読み方
  2. 8.2 journalctlによる詳細なログ確認
    1. 8.2.1 journaldとrsyslogの関係
    2. 8.2.2 journalctlの基本オプション(復習)
    3. 8.2.3 時間範囲でのフィルタリング
    4. 8.2.4 優先度でのフィルタリング
    5. 8.2.5 ユニット単位でのフィルタリング(-u)
    6. 8.2.6 カーネルメッセージ(-k)
    7. 8.2.7 ブート単位でのログ表示(-b)
    8. 8.2.8 ログのエクスポート(-o)
    9. 8.2.9 リアルタイム監視(-f)とgrepの組み合わせ
  3. 8.3 トラブルシューティングの基本手順
    1. 8.3.1 問題の切り分けプロセス
    2. 8.3.2 「5W1H」でログを読む
    3. 8.3.3 エラーメッセージのGoogle検索テクニック
  4. 8.4 ケーススタディ1: サービスが起動しない
    1. 8.4.1 症状の確認
    2. 8.4.2 systemctl statusでステータス確認
    3. 8.4.3 journalctl -xeでログ確認
    4. 8.4.4 設定ファイルの構文チェック
    5. 8.4.5 パーミッション問題の確認
    6. 8.4.6 SELinuxの確認
    7. 8.4.7 ポート競合の確認
    8. 8.4.8 段階的な問題解決
  5. 8.5 ケーススタディ2: ネットワークに繋がらない
    1. 8.5.1 症状の確認(どこまで通るか)
    2. 8.5.2 インターフェース状態確認(ip link)
    3. 8.5.3 IPアドレス確認(ip addr)
    4. 8.5.4 ゲートウェイへのping
    5. 8.5.5 DNS解決確認(dig, nslookup)
    6. 8.5.6 ファイアウォール確認
    7. 8.5.7 ルーティング確認(ip route)
    8. 8.5.8 段階的な問題解決
  6. 8.6 ケーススタディ3: ディスク容量不足
    1. 8.6.1 df -hで容量確認
    2. 8.6.2 容量を消費している場所の特定
    3. 8.6.3 du -sh /*で大まかな把握
    4. 8.6.4 du -ah /var | sort -rh | head -20で詳細特定
    5. 8.6.5 ログファイルの肥大化対応
    6. 8.6.6 tmpファイルの削除
    7. 8.6.7 パッケージキャッシュのクリア
    8. 8.6.8 恒久対応(ログローテーション設定等)
  7. 8.7 システムリソースの監視
    1. 8.7.1 なぜ監視が必要か
    2. 8.7.2 topコマンドでプロセス監視
    3. 8.7.3 htopによる視覚的な監視(推奨)
    4. 8.7.4 freeでメモリ使用量確認
    5. 8.7.5 dfでディスク使用量確認
    6. 8.7.6 uptimeでシステム負荷確認
  8. 8.8 プロセス管理
    1. 8.8.1 プロセスとは
    2. 8.8.2 psコマンドでプロセス一覧
    3. 8.8.3 pgrepで名前からプロセス検索
    4. 8.8.4 killでプロセス終了
    5. 8.8.5 killall, pkillの使い方
  9. 8.9 高度なトラブルシューティングツール
    1. 8.9.1 lsof – ファイルを開いているプロセスを特定
    2. 8.9.2 strace – システムコールのトレース
    3. 8.9.3 tcpdump – ネットワークパケットキャプチャ
    4. 8.9.4 dmesg – カーネルメッセージ
    5. 8.9.5 パフォーマンス分析ツール
  10. 8.10 実践的なトラブルシューティング演習
    1. 8.10.1 意図的に問題を起こして解決する
    2. 8.10.2 ログから原因を特定する思考プロセス
    3. 8.10.3 問題解決後の検証方法
    4. 8.10.4 再発防止策の検討
    5. 8.10.5 ドキュメント化の重要性
    6. 【コラム7】ログを読まずに5時間無駄にした話
  11. 章末まとめ
    1. 学んだこと
    2. 重要なコマンド
  12. 練習問題
  13. 次章への橋渡し

8.1 ログファイルの基礎

まず、Linuxシステムでログがどのように管理されているかを理解しましょう。

8.1.1 なぜログが重要なのか

ログが重要な理由は主に3つあります。

1. 問題の原因特定

サービスが動かないとき、ログには具体的なエラーメッセージが記録されています。「設定ファイルの42行目に構文エラーがあります」といった情報があれば、すぐに対処できます。

2. セキュリティ監視

不正アクセスの試みや、異常な動作はログに記録されます。「192.168.1.100から100回のSSHログイン失敗」という記録があれば、攻撃を受けていることがわかります。

3. 監査証跡

「いつ、誰が、何をしたか」を後から確認できます。トラブル発生時の原因究明や、コンプライアンス対応に不可欠です。

💡 実務のヒント: 「問題が起きたら、まずログを見る」を習慣にしてください。この習慣があるかないかで、トラブルシューティングの効率は10倍変わります。

8.1.2 /var/logディレクトリの構成

Linuxのログファイルは、/var/log/ディレクトリに集約されています。どのようなファイルがあるか確認してみましょう。

[実行ユーザー: 一般ユーザー]

$ ls -la /var/log/
total 2048
drwxr-xr-x. 10 root root    4096 Jan 15 10:00 .
drwxr-xr-x. 22 root root    4096 Jan 10 12:00 ..
drwxr-x---.  2 root root    4096 Jan 15 00:00 audit
-rw-------.  1 root root   12345 Jan 15 14:30 boot.log
-rw-------.  1 root root    8765 Jan 15 10:00 cron
drwxr-xr-x.  2 root root    4096 Jan 15 00:00 httpd
drwx------.  2 root root    4096 Jan 10 12:00 journal
-rw-r--r--.  1 root root  123456 Jan 15 14:30 messages
drwxr-xr-x.  2 root root    4096 Jan 10 12:00 nginx
-rw-------.  1 root root   56789 Jan 15 14:30 secure
-rw-------.  1 root root   12345 Jan 15 14:30 dnf.log

/var/log/には、システム全体のログとアプリケーション固有のログが混在しています。ディレクトリ構造を理解しておくと、必要なログをすぐに見つけられます。

8.1.3 主要なログファイル

AlmaLinux 10で重要なログファイルを紹介します。

ファイル 内容 用途
/var/log/messages システム全般のログ 一般的なトラブルシューティング
/var/log/secure 認証関連のログ ログイン試行、sudo実行の確認
/var/log/audit/audit.log SELinux監査ログ SELinux拒否の原因特定
/var/log/cron cronの実行ログ 定期実行ジョブの確認
/var/log/dnf.log パッケージ管理のログ インストール・更新履歴
/var/log/boot.log 起動時のログ 起動時の問題調査

/var/log/messages – システム全般のログ

最も汎用的なログファイルです。カーネルメッセージ、サービスの状態変化、ハードウェアの検出など、さまざまな情報が記録されます。

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo tail -20 /var/log/messages
Jan 15 14:25:00 server1 systemd[1]: Starting httpd.service - The Apache HTTP Server...
Jan 15 14:25:01 server1 httpd[12345]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name
Jan 15 14:25:01 server1 systemd[1]: Started httpd.service - The Apache HTTP Server.
Jan 15 14:30:00 server1 NetworkManager[789]: <info>  [1705296600] device (enp0s3): state change: activated -> unavailable
Jan 15 14:30:05 server1 kernel: enp0s3: link down

/var/log/secure – 認証関連のログ

SSHログイン、sudo実行、ユーザー切り替えなど、認証に関するイベントが記録されます。セキュリティ監視の要となるログです。

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo tail -10 /var/log/secure
Jan 15 14:20:00 server1 sshd[5678]: Accepted publickey for developer from 192.168.1.50 port 52345 ssh2
Jan 15 14:20:00 server1 sshd[5678]: pam_unix(sshd:session): session opened for user developer
Jan 15 14:25:30 server1 sudo[6789]: developer : TTY=pts/0 ; PWD=/home/developer ; USER=root ; COMMAND=/bin/systemctl restart httpd
Jan 15 14:28:00 server1 sshd[9999]: Failed password for invalid user admin from 203.0.113.50 port 54321 ssh2
Jan 15 14:28:05 server1 sshd[9999]: Failed password for invalid user admin from 203.0.113.50 port 54321 ssh2

上記の例では、正常なログインと、不正なログイン試行(存在しないユーザー「admin」へのパスワード攻撃)の両方が記録されています。

/var/log/audit/audit.log – SELinux監査ログ

SELinuxがアクセスを拒否した記録が残ります。第7章で学んだSELinux問題の調査に使用します。

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo tail -5 /var/log/audit/audit.log
type=AVC msg=audit(1705296600.123:456): avc:  denied  { read } for  pid=12345 comm="httpd" name="custom.conf" dev="sda1" ino=67890 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0

このログは「httpdがcustom.confを読もうとしたが、SELinuxに拒否された」ことを示しています。

8.1.4 ログの世代管理(logrotate)

ログファイルは放置すると際限なく大きくなり、ディスク容量を圧迫します。logrotateは、ログファイルを定期的にローテーション(世代管理)するツールです。

[実行ユーザー: 一般ユーザー]

$ ls -la /var/log/messages*
-rw-r--r--. 1 root root  123456 Jan 15 14:30 /var/log/messages
-rw-r--r--. 1 root root  234567 Jan 14 23:59 /var/log/messages-20260114
-rw-r--r--. 1 root root  345678 Jan 13 23:59 /var/log/messages-20260113

logrotateの動作により、古いログは日付付きのファイル名で保存され、一定期間後に削除されます。設定は/etc/logrotate.conf/etc/logrotate.d/で管理されています。

[実行ユーザー: 一般ユーザー]

# メイン設定ファイルの確認
$ cat /etc/logrotate.conf
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# uncomment this if you want your log files compressed
compress

# packages drop log rotation information into this directory
include /etc/logrotate.d

主な設定項目は以下の通りです。

  • weekly: 毎週ローテーション
  • rotate 4: 4世代保持(それより古いものは削除)
  • compress: 古いログをgzip圧縮
  • dateext: ローテーション時に日付をファイル名に付加

8.1.5 ログのタイムスタンプの読み方

ログのタイムスタンプを正確に読むことは、問題発生時刻の特定に不可欠です。


年が記録されていないことに注意してください。年をまたぐ問題の調査では、ファイルの更新日時も確認する必要があります。

💡 実務のヒント: journalctlを使えば年も含めたタイムスタンプで確認できます。複雑な調査ではjournalctlを優先的に使いましょう。

8.2 journalctlによる詳細なログ確認

第5章でjournalctlの基本を学びました。この節では、より実践的なオプションと組み合わせテクニックを習得します。

8.2.1 journaldとrsyslogの関係

AlmaLinux 10では、2つのログシステムが併存しています。


journaldが中心となりログを収集し、rsyslogに転送することで従来のテキストログも生成されます。

項目 journalctl 従来のログファイル
検索 高速(インデックス付き) grep依存(大きいと遅い)
フィルタ 多彩(時間、優先度、サービス等) grepで工夫が必要
可読性 コマンドが必要 直接読める
転送 設定が複雑 rsyslogで容易
スクリプト連携 JSON出力で可能 テキスト処理が容易

実務では状況に応じて使い分けますが、トラブルシューティングではjournalctlを優先的に使うことを推奨します。

8.2.2 journalctlの基本オプション(復習)

第5章で学んだ基本オプションを簡単に復習します。

[実行ユーザー: 一般ユーザー]

# 特定サービスのログ
$ journalctl -u httpd

# リアルタイム監視
$ journalctl -f

# 最新のn行を表示
$ journalctl -n 50

# 末尾から表示(ページャーで最後に移動)
$ journalctl -e

8.2.3 時間範囲でのフィルタリング

トラブルシューティングでは、問題発生時刻の前後に絞ってログを確認することが重要です。

–since オプション(開始時刻)

[実行ユーザー: 一般ユーザー]

# 特定の日時以降
$ journalctl --since "2026-01-15 14:00:00"

# 相対指定(1時間前から)
$ journalctl --since "1 hour ago"

# 相対指定(30分前から)
$ journalctl --since "30 minutes ago"

# 昨日から
$ journalctl --since yesterday

# 今日の0時から
$ journalctl --since today

–until オプション(終了時刻)

[実行ユーザー: 一般ユーザー]

# 特定の日時まで
$ journalctl --until "2026-01-15 15:00:00"

# 相対指定(10分前まで)
$ journalctl --until "10 minutes ago"

範囲指定の組み合わせ

[実行ユーザー: 一般ユーザー]

# 14:00から15:00までの1時間
$ journalctl --since "2026-01-15 14:00:00" --until "2026-01-15 15:00:00"

# 1時間前から30分前までの30分間
$ journalctl --since "1 hour ago" --until "30 minutes ago"

# 特定サービスの直近1時間
$ journalctl -u httpd --since "1 hour ago"

8.2.4 優先度でのフィルタリング

-pオプションで、ログの重要度(優先度)をフィルタリングできます。

優先度 数値 意味 対処
emerg 0 システム使用不能 即座に対処
alert 1 即座にアクション必要 即座に対処
crit 2 危機的な状態 早急に対処
err 3 エラー状態 対処が必要
warning 4 警告状態 注意が必要
notice 5 正常だが重要な状態 参考情報
info 6 情報メッセージ 参考情報
debug 7 デバッグメッセージ 開発時のみ

[実行ユーザー: 一般ユーザー]

# エラー以上(emerg, alert, crit, err)を表示
$ journalctl -p err

# 警告以上を表示
$ journalctl -p warning

# 特定サービスのエラーのみ
$ journalctl -u httpd -p err

# 直近1時間のエラー
$ journalctl -p err --since "1 hour ago"

トラブルシューティングでは、まず-p errでエラーを確認し、必要に応じて-p warningに範囲を広げるのが効率的です。

8.2.5 ユニット単位でのフィルタリング(-u)

特定のサービス(ユニット)のログだけを表示します。複数のサービスを同時に指定することもできます。

[実行ユーザー: 一般ユーザー]

# 単一サービス
$ journalctl -u httpd

# 複数サービス
$ journalctl -u httpd -u mariadb

# サービスの直近のエラー
$ journalctl -u sshd -p err --since "1 hour ago"

8.2.6 カーネルメッセージ(-k)

カーネルが出力するメッセージのみを表示します。ハードウェアの問題やドライバの問題を調査するときに使います。

[実行ユーザー: 一般ユーザー]

$ journalctl -k
-- Logs begin at Wed 2026-01-01 00:00:00 JST, end at Wed 2026-01-15 14:30:00 JST. --
Jan 15 10:00:00 server1 kernel: Linux version 6.12.0-1.el10.x86_64 ...
Jan 15 10:00:01 server1 kernel: Command line: BOOT_IMAGE=(hd0,gpt2)/vmlinuz-6.12.0-1.el10.x86_64 ...
Jan 15 10:00:02 server1 kernel: Memory: 3936MB available
Jan 15 14:25:00 server1 kernel: enp0s3: link down
Jan 15 14:25:05 server1 kernel: enp0s3: link up, 1000Mbps full-duplex

ネットワークインターフェースの状態変化(link down/up)もカーネルメッセージとして記録されます。

8.2.7 ブート単位でのログ表示(-b)

システムの起動(ブート)単位でログを絞り込めます。「再起動してから問題が発生した」という状況で有用です。

[実行ユーザー: 一般ユーザー]

# 現在のブートのログ
$ journalctl -b

# 前回のブートのログ
$ journalctl -b -1

# 2回前のブートのログ
$ journalctl -b -2

# 利用可能なブート一覧
$ journalctl --list-boots
-2 abc123def456 Wed 2026-01-13 10:00:00 JST—Wed 2026-01-13 23:59:59 JST
-1 789xyz012345 Thu 2026-01-14 10:00:00 JST—Thu 2026-01-14 23:59:59 JST
 0 456abc789def Fri 2026-01-15 10:00:00 JST—Fri 2026-01-15 14:30:00 JST

⚠️ 注意: 過去のブートログを確認するには、ログの永続化設定が必要です(第5章参照)。永続化されていない場合、現在のブートのログしか表示できません。

8.2.8 ログのエクスポート(-o)

ログを様々な形式で出力できます。スクリプトでの処理や、他の人との共有に便利です。

[実行ユーザー: 一般ユーザー]

# JSON形式(スクリプト処理向け)
$ journalctl -u httpd -o json-pretty --since "1 hour ago"
{
    "__CURSOR" : "s=abc123...",
    "PRIORITY" : "6",
    "_HOSTNAME" : "server1",
    "MESSAGE" : "AH00558: httpd: Could not reliably determine...",
    "_SYSTEMD_UNIT" : "httpd.service",
    ...
}

# 短縮形式(1行1メッセージ)
$ journalctl -u httpd -o short

# 詳細形式(全フィールド表示)
$ journalctl -u httpd -o verbose

# cat形式(メッセージのみ)
$ journalctl -u httpd -o cat

主な出力フォーマットは以下の通りです。

フォーマット 説明 用途
short デフォルト(syslog風) 通常の確認
short-precise マイクロ秒単位の時刻 精密な時刻確認
json JSON形式(1行1オブジェクト) スクリプト処理
json-pretty JSON形式(整形済み) 人間が読む場合
verbose 全メタデータ表示 詳細調査
cat メッセージ本文のみ テキスト処理

8.2.9 リアルタイム監視(-f)とgrepの組み合わせ

実務では、journalctlとgrepを組み合わせて使うことが多くあります。

[実行ユーザー: 一般ユーザー]

# 特定キーワードを含むログをリアルタイム監視
$ journalctl -f | grep -i error

# 特定サービスのエラーをリアルタイム監視
$ journalctl -u httpd -f | grep -i "failed\|error"

# IPアドレスを含むログを抽出
$ journalctl -u sshd --since "1 hour ago" | grep "192.168.1"

# 特定のエラーコードを検索
$ journalctl -u httpd --since today | grep "AH00"

複数条件の組み合わせ例

[実行ユーザー: 一般ユーザー]

# 直近1時間のhttpdのエラーで、"permission"を含むもの
$ journalctl -u httpd -p err --since "1 hour ago" | grep -i permission

# 今日のSSHログイン失敗
$ journalctl -u sshd --since today | grep -i "failed\|invalid"

# カーネルのネットワーク関連メッセージ
$ journalctl -k --since "30 minutes ago" | grep -i "link\|network\|eth\|enp"

💡 実務のヒント: journalctlで大まかに絞り込み、grepで細かく検索するのが効率的です。journalctlのフィルタだけで十分な場合も多いですが、複雑な検索にはgrepを組み合わせましょう。

8.3 トラブルシューティングの基本手順

ツールの使い方を学んだところで、トラブルシューティングの「考え方」を身につけましょう。

8.3.1 問題の切り分けプロセス

トラブルシューティングは、以下の流れで進めます。

 

この流れを意識することで、闇雲に対処して時間を浪費することを防げます。

8.3.2 「5W1H」でログを読む

ログを読むときは、以下の観点で情報を整理します。

  • When(いつ): 問題が発生した時刻
  • Where(どこで): どのサーバー、どのサービス
  • Who(誰が): どのユーザー、どのプロセス
  • What(何が): 何が起きたか(エラーの内容)
  • Why(なぜ): なぜ起きたか(原因)
  • How(どのように): どのように対処すべきか

例: ログメッセージの分析

Jan 15 14:25:30 server1 httpd[12345]: AH00526: Syntax error on line 42 of /etc/httpd/conf/httpd.conf:
  • When: 1月15日 14:25:30
  • Where: server1のhttpdサービス
  • Who: プロセスID 12345
  • What: 構文エラー(Syntax error)
  • Why: /etc/httpd/conf/httpd.confの42行目に問題がある
  • How: 設定ファイルの42行目を確認・修正する

このように整理すると、次に何をすべきかが明確になります。

8.3.3 エラーメッセージのGoogle検索テクニック

エラーメッセージをそのままGoogle検索するのは有効なテクニックです。ただし、いくつかのコツがあります。

効果的な検索方法

  1. エラーコードを含める: 「AH00526」「error code 1」など
  2. ホスト名やパスを除外: 固有の情報は検索ノイズになる
  3. 引用符で囲む: 完全一致で検索できる
  4. OS名を追加: 「AlmaLinux」「RHEL」を追加すると精度が上がる

検索例

元のエラーメッセージ:
AH00526: Syntax error on line 42 of /etc/httpd/conf/httpd.conf: Invalid command 'ServerNam'

検索クエリ:
"AH00526" "Invalid command" httpd AlmaLinux

検索結果から、同じ問題に遭遇した人の解決策を見つけられることが多いです。Stack Overflow、Red Hat Knowledge Base、各種技術ブログなどが参考になります。

⚠️ 注意: 検索で見つけた解決策をそのまま適用するのは危険です。自分の環境に適しているか、副作用はないかを確認してから実行しましょう。特にchmod 777setenforce 0などの「とりあえず動く」解決策は、セキュリティリスクを伴います。

8.4 ケーススタディ1: サービスが起動しない

ここからは、実際のトラブル事例を通じてトラブルシューティングの流れを体験します。

8.4.1 症状の確認

状況: httpdサービスを起動しようとしたが、失敗する。

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo systemctl start httpd
Job for httpd.service failed because the control process exited with error code.
See "systemctl status httpd.service" and "journalctl -xeu httpd.service" for details.

エラーメッセージが親切にも「systemctl status」と「journalctl -xe」を見るよう指示してくれています。この指示に従いましょう。

8.4.2 systemctl statusでステータス確認

[実行ユーザー: 一般ユーザー]

$ systemctl status httpd
× httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
     Active: failed (Result: exit-code) since Wed 2026-01-15 14:30:00 JST; 1min ago
       Docs: man:httpd.service(8)
    Process: 12345 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE)
   Main PID: 12345 (code=exited, status=1/FAILURE)
        CPU: 15ms

Jan 15 14:30:00 server1 systemd[1]: Starting httpd.service - The Apache HTTP Server...
Jan 15 14:30:00 server1 httpd[12345]: AH00526: Syntax error on line 42 of /etc/httpd/conf/httpd.conf:
Jan 15 14:30:00 server1 httpd[12345]: Invalid command 'ServerNam', perhaps misspelled or defined by a module not included in the server configuration
Jan 15 14:30:00 server1 systemd[1]: httpd.service: Main process exited, code=exited, status=1/FAILURE
Jan 15 14:30:00 server1 systemd[1]: httpd.service: Failed with result 'exit-code'.
Jan 15 14:30:00 server1 systemd[1]: Failed to start httpd.service - The Apache HTTP Server.

ログから以下のことがわかります。

  • サービスは「failed」状態
  • 原因は「Syntax error on line 42」(構文エラー)
  • 具体的には「Invalid command ‘ServerNam’」(無効なコマンド)

「ServerNam」は「ServerName」のタイプミス(typo)だと推測できます。

8.4.3 journalctl -xeでログ確認

より詳しい情報を得るため、journalctlも確認します。

[実行ユーザー: 一般ユーザー]

$ journalctl -xeu httpd
Jan 15 14:30:00 server1 systemd[1]: Starting httpd.service - The Apache HTTP Server...
░░ Subject: A start job for unit httpd.service has begun execution
░░ Defined-By: systemd
░░ Support: https://wiki.almalinux.org
░░
░░ A start job for unit httpd.service has begun execution.
░░
░░ The job identifier is 1234.
Jan 15 14:30:00 server1 httpd[12345]: AH00526: Syntax error on line 42 of /etc/httpd/conf/httpd.conf:
Jan 15 14:30:00 server1 httpd[12345]: Invalid command 'ServerNam', perhaps misspelled or defined by a module not included in the server configuration
Jan 15 14:30:00 server1 systemd[1]: httpd.service: Main process exited, code=exited, status=1/FAILURE
░░ Subject: Unit process exited
...

-xオプションにより、追加の説明(░░で始まる行)が表示されています。

8.4.4 設定ファイルの構文チェック

問題箇所がわかったので、設定ファイルを確認します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# 42行目付近を確認
$ sudo sed -n '40,45p' /etc/httpd/conf/httpd.conf
# ServerName gives the name and port that the server uses to identify itself.
#
ServerNam www.example.com:80

#
# Deny access to the entirety of your server's filesystem.

42行目に「ServerNam」と書かれています。「e」が抜けています。

Apacheには構文チェックコマンドがあるので、それも使ってみましょう。

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo apachectl configtest
AH00526: Syntax error on line 42 of /etc/httpd/conf/httpd.conf:
Invalid command 'ServerNam', perhaps misspelled or defined by a module not included in the server configuration

構文チェックでも同じエラーが報告されます。

8.4.5 パーミッション問題の確認

構文エラーが原因でしたが、パーミッション問題の可能性も確認しておきましょう。パーミッション問題の場合は、以下のようなエラーになります。

# パーミッション問題の例
$ journalctl -u httpd -p err
Jan 15 14:35:00 server1 httpd[12346]: (13)Permission denied: AH00091: httpd: could not open error log file /var/log/httpd/error_log

このような場合は、ファイルやディレクトリの権限を確認します。

[実行ユーザー: 一般ユーザー]

$ ls -la /var/log/httpd/
total 8
drwx------. 2 root root 4096 Jan 15 10:00 .
drwxr-xr-x. 10 root root 4096 Jan 15 10:00 ..
-rw-r--r--. 1 root root    0 Jan 15 10:00 access_log
-rw-r--r--. 1 root root    0 Jan 15 10:00 error_log

8.4.6 SELinuxの確認

第7章で学んだSELinuxが原因の場合もあります。SELinux拒否のログを確認します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# 直近のSELinux拒否を確認
$ sudo ausearch -m AVC -ts recent
<no matches>

# または audit.log を直接確認
$ sudo grep "denied" /var/log/audit/audit.log | tail -5

今回はSELinuxの拒否はありませんでした。SELinuxが原因の場合は、以下のようなログが記録されます。

# SELinux拒否の例
type=AVC msg=audit(1705296600.123:456): avc:  denied  { read } for  pid=12345 comm="httpd" name="custom.conf" ...

8.4.7 ポート競合の確認

別のプロセスが同じポートを使っている場合も起動に失敗します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# ポート80を使用しているプロセスを確認
$ sudo ss -tlnp | grep :80
LISTEN 0      128          *:80          *:*    users:(("nginx",pid=9876,fd=6))

もしnginxなど別のWebサーバーがポート80を使っている場合、httpdは起動できません。

ポート競合時のエラーは以下のようになります。

# ポート競合の例
Jan 15 14:40:00 server1 httpd[12347]: (98)Address already in use: AH00072: make_sock: could not bind to address [::]:80

8.4.8 段階的な問題解決

今回のケースでは、原因は設定ファイルのタイプミスでした。修正しましょう。

[実行ユーザー: 一般ユーザー(sudo使用)]

# 設定ファイルを修正
$ sudo vi /etc/httpd/conf/httpd.conf
# 42行目の "ServerNam" を "ServerName" に修正

# 構文チェック
$ sudo apachectl configtest
Syntax OK

# サービス起動
$ sudo systemctl start httpd

# 状態確認
$ systemctl status httpd
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
     Active: active (running) since Wed 2026-01-15 14:45:00 JST; 5s ago
     ...

問題が解決しました。

💡 学んだこと:

  • エラーメッセージを読めば、多くの場合原因がわかる
  • systemctl statusjournalctl -xeはセットで使う
  • 設定変更後は必ず構文チェックを行う
  • 問題の切り分けは段階的に行う(構文→パーミッション→SELinux→ポート競合)

8.5 ケーススタディ2: ネットワークに繋がらない

次は、ネットワーク接続の問題を解決します。

8.5.1 症状の確認(どこまで通るか)

状況: サーバーからインターネットに接続できない。

まず、「どこまで通信できているか」を確認することが重要です。

[実行ユーザー: 一般ユーザー]

$ ping 8.8.8.8
ping: connect: Network is unreachable

「Network is unreachable」は、ネットワーク自体に到達できない状態です。レイヤーの低いところから順に確認していきます。

8.5.2 インターフェース状態確認(ip link)

まず、ネットワークインターフェースが有効になっているか確認します。

[実行ユーザー: 一般ユーザー]

$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel state DOWN mode DEFAULT group default qlen 1000
    link/ether 08:00:27:xx:xx:xx brd ff:ff:ff:ff:ff:ff

enp0s3のstateが「DOWN」になっています。これが原因です。

  • UP: インターフェースが有効
  • DOWN: インターフェースが無効

8.5.3 IPアドレス確認(ip addr)

IPアドレスが割り当てられているかも確認します。

[実行ユーザー: 一般ユーザー]

$ ip addr show enp0s3
2: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 08:00:27:xx:xx:xx brd ff:ff:ff:ff:ff:ff

「inet」の行がありません。IPアドレスが設定されていません。

正常な場合は以下のように表示されます。

$ ip addr show enp0s3
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s3
       valid_lft 86400sec preferred_lft 86400sec

8.5.4 ゲートウェイへのping

インターフェースが有効でIPアドレスが設定されている場合は、ゲートウェイへの到達性を確認します。

[実行ユーザー: 一般ユーザー]

# ルーティングテーブルでゲートウェイを確認
$ ip route
default via 192.168.1.1 dev enp0s3 proto dhcp metric 100
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.100 metric 100

# ゲートウェイにping
$ ping -c 3 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.5 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.4 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.4 ms

ゲートウェイに到達できれば、ローカルネットワークは正常です。

8.5.5 DNS解決確認(dig, nslookup)

ゲートウェイまで到達でき、外部へのpingも通る場合は、DNS解決を確認します。

[実行ユーザー: 一般ユーザー]

# digコマンドでDNS解決を確認
$ dig google.com +short
142.250.196.110

# nslookupでも確認可能
$ nslookup google.com
Server:         192.168.1.1
Address:        192.168.1.1#53

Non-authoritative answer:
Name:   google.com
Address: 142.250.196.110

DNS解決ができない場合は、/etc/resolv.confを確認します。

[実行ユーザー: 一般ユーザー]

$ cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 192.168.1.1

8.5.6 ファイアウォール確認

内部からの通信がブロックされていないか確認します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# 現在のファイアウォール設定
$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3
  sources: 
  services: cockpit dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

outgoing(外向き)の通信は通常ブロックされませんが、incoming(内向き)の通信で問題が発生することがあります。

8.5.7 ルーティング確認(ip route)

ルーティングテーブルに問題がないか確認します。

[実行ユーザー: 一般ユーザー]

$ ip route
default via 192.168.1.1 dev enp0s3 proto dhcp metric 100
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.100 metric 100

「default via」の行がなければ、デフォルトゲートウェイが設定されていません。

8.5.8 段階的な問題解決

今回のケースでは、インターフェースがDOWNになっていました。NetworkManagerで有効化します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# 接続プロファイルを確認
$ nmcli connection show
NAME    UUID                                  TYPE      DEVICE 
enp0s3  12345678-1234-1234-1234-123456789012  ethernet  --

# 接続を有効化
$ sudo nmcli connection up enp0s3
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/1)

# 状態を確認
$ ip addr show enp0s3
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s3
       valid_lft 86399sec preferred_lft 86399sec

# 疎通確認
$ ping -c 3 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=117 time=10.5 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=117 time=9.8 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=117 time=10.1 ms

問題が解決しました。

💡 ネットワーク問題の切り分け順序:

  1. 物理層: ケーブルは繋がっているか、インターフェースはUPか
  2. ネットワーク層: IPアドレスは設定されているか
  3. ルーティング: デフォルトゲートウェイは設定されているか、到達できるか
  4. 外部接続: 外部ホスト(8.8.8.8等)にpingが通るか
  5. DNS: 名前解決ができるか
  6. アプリケーション: 特定のポートがファイアウォールでブロックされていないか

8.6 ケーススタディ3: ディスク容量不足

最後に、ディスク容量不足の問題を解決します。

8.6.1 df -hで容量確認

状況: サービスが動作しなくなり、ログに「No space left on device」と記録されている。

[実行ユーザー: 一般ユーザー]

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           783M  9.5M  773M   2% /run
/dev/sda3        50G   50G     0 100% /
/dev/sda2       960M  224M  736M  24% /boot
/dev/sda1       599M  7.0M  592M   2% /boot/efi
tmpfs           392M     0  392M   0% /run/user/1000

ルートパーティション(/)が100%使用になっています。これが問題です。

8.6.2 容量を消費している場所の特定

「何が」ディスクを消費しているかを特定します。

8.6.3 du -sh /*で大まかな把握

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo du -sh /* 2>/dev/null | sort -rh | head -10
35G     /var
8.5G    /usr
2.1G    /home
1.2G    /opt
512M    /boot
128M    /etc
64M     /root
32M     /tmp
...

/varが35GB消費しています。さらに掘り下げます。

8.6.4 du -ah /var | sort -rh | head -20で詳細特定

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo du -sh /var/* 2>/dev/null | sort -rh | head -10
32G     /var/log
1.5G    /var/cache
800M    /var/lib
256M    /var/tmp
...

$ sudo du -sh /var/log/* 2>/dev/null | sort -rh | head -10
30G     /var/log/httpd
1.2G    /var/log/messages
512M    /var/log/secure
256M    /var/log/audit
...

$ sudo ls -lh /var/log/httpd/
total 30G
-rw-r--r--. 1 root root  28G Jan 15 14:30 access_log
-rw-r--r--. 1 root root 2.0G Jan 15 14:30 error_log

Apache(httpd)のaccess_logが28GBになっています。これが原因です。

8.6.5 ログファイルの肥大化対応

巨大なログファイルを確認してから、対処を決めます。

[実行ユーザー: 一般ユーザー(sudo使用)]

# ログの末尾を確認(何が大量に記録されているか)
$ sudo tail -20 /var/log/httpd/access_log
192.168.1.50 - - [15/Jan/2026:14:30:00 +0900] "GET /health HTTP/1.1" 200 2
192.168.1.50 - - [15/Jan/2026:14:30:01 +0900] "GET /health HTTP/1.1" 200 2
192.168.1.50 - - [15/Jan/2026:14:30:02 +0900] "GET /health HTTP/1.1" 200 2
...

ヘルスチェックが1秒ごとに記録されており、これが大量のログの原因でした。

応急処置: ログファイルのトランケート(切り詰め)

[実行ユーザー: 一般ユーザー(sudo使用)]

# 削除ではなくトランケート(ファイルを空にする)
# 削除するとhttpdがログを書けなくなる可能性がある
$ sudo truncate -s 0 /var/log/httpd/access_log

# 容量を確認
$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        50G   22G   28G  44% /

🚨 注意: rmでログファイルを削除すると、サービスが開いているファイルハンドルが残り、ディスク容量が解放されないことがあります。truncateでファイルを空にするか、サービスを再起動してからファイルを削除してください。

8.6.6 tmpファイルの削除

一時ファイルが溜まっている場合もあります。

[実行ユーザー: 一般ユーザー(sudo使用)]

# tmpディレクトリの確認
$ sudo du -sh /tmp /var/tmp
256M    /tmp
128M    /var/tmp

# 古いtmpファイルの削除(7日以上前のファイル)
$ sudo find /tmp -type f -mtime +7 -delete
$ sudo find /var/tmp -type f -mtime +7 -delete

8.6.7 パッケージキャッシュのクリア

dnfのキャッシュも容量を消費します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# キャッシュのサイズ確認
$ sudo du -sh /var/cache/dnf
1.5G    /var/cache/dnf

# キャッシュのクリア
$ sudo dnf clean all
45 files removed

# 確認
$ sudo du -sh /var/cache/dnf
12K     /var/cache/dnf

8.6.8 恒久対応(ログローテーション設定等)

応急処置だけでは、また同じ問題が発生します。恒久対策を講じましょう。

httpdのログローテーション設定

[実行ユーザー: 一般ユーザー(sudo使用)]

# 現在の設定を確認
$ cat /etc/logrotate.d/httpd
/var/log/httpd/*log {
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true
    endscript
}

設定を改善します。

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo vi /etc/logrotate.d/httpd
/var/log/httpd/*log {
    daily                   # 毎日ローテーション
    rotate 7                # 7世代保持
    compress               # 古いログを圧縮
    delaycompress          # 1世代前から圧縮
    missingok              # ファイルがなくてもエラーにしない
    notifempty             # 空ファイルはローテーションしない
    size 100M              # 100MB超えたらローテーション
    sharedscripts
    postrotate
        /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true
    endscript
}

主な設定項目は以下の通りです。

  • daily: 毎日ローテーション(weekly、monthlyも可)
  • rotate 7: 7世代保持(それより古いものは削除)
  • compress: gzipで圧縮
  • size 100M: 100MBを超えたらローテーション(時間に関係なく)

ディスク容量監視の設定

第7章で学んだシェルスクリプトを使って、ディスク容量を監視するスクリプトを作成することも有効です。これについては第9章でも詳しく扱います。

💡 学んだこと:

  • df -hでディスク全体の使用状況を把握
  • du -shで原因となるディレクトリを特定
  • ログファイルはrmではなくtruncateで空にする
  • 恒久対策としてログローテーションを適切に設定

8.7 システムリソースの監視

トラブルシューティングでは、システムリソース(CPU、メモリ、ディスクI/O)の状態確認も重要です。

8.7.1 なぜ監視が必要か

システムリソースの監視は、以下の目的で行います。

  • 問題の早期発見: 異常を検知して障害を未然に防ぐ
  • 原因の特定: パフォーマンス低下の原因を把握する
  • キャパシティプランニング: リソースの増強時期を判断する
  • 異常検知: 通常とは異なる動作(攻撃など)を検知する

8.7.2 topコマンドでプロセス監視

topは、リアルタイムでシステムの状態を表示するコマンドです。

[実行ユーザー: 一般ユーザー]

$ top
top - 14:30:00 up 2 days,  3:45,  2 users,  load average: 0.15, 0.10, 0.05
Tasks: 128 total,   1 running, 127 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.3 us,  1.0 sy,  0.0 ni, 96.5 id,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   3936.0 total,   1234.5 free,   1456.7 used,   1244.8 buff/cache
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   2156.3 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   1234 root      20   0  456789  12345   6789 S   2.0   0.3   0:15.67 httpd
   5678 mysql     20   0  987654  56789  12345 S   1.5   1.4   5:23.45 mysqld
   9012 root      20   0   12345   3456   2345 R   0.5   0.1   0:00.12 top
      1 root      20   0  171234   9876   6543 S   0.0   0.2   0:05.67 systemd
    ...

ヘッダー部分の読み方

top - 14:30:00 up 2 days,  3:45,  2 users,  load average: 0.15, 0.10, 0.05
       │         │              │          └─ ロードアベレージ(1分、5分、15分平均)
       │         │              └─ ログインユーザー数
       │         └─ システム稼働時間
       └─ 現在時刻
%Cpu(s):  2.3 us,  1.0 sy,  0.0 ni, 96.5 id,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
          │        │        │       │        │        │        │        └─ steal(仮想化オーバーヘッド)
          │        │        │       │        │        │        └─ softirq(ソフト割込み)
          │        │        │       │        │        └─ hardirq(ハード割込み)
          │        │        │       │        └─ iowait(I/O待ち)
          │        │        │       └─ idle(アイドル)
          │        │        └─ nice(優先度変更プロセス)
          │        └─ system(カーネル)
          └─ user(ユーザープロセス)

topの操作方法

キー 動作
q 終了
M メモリ使用量でソート
P CPU使用率でソート
k プロセスをkill(PIDを入力)
1 CPU別の使用率表示
h ヘルプ表示

8.7.3 htopによる視覚的な監視(推奨)

htopは、topの機能強化版です。カラフルで見やすく、マウス操作にも対応しています。

インストール

[実行ユーザー: 一般ユーザー(sudo使用)]

# EPELリポジトリからインストール
$ sudo dnf install epel-release
$ sudo dnf install htop

実行

[実行ユーザー: 一般ユーザー]

$ htop

htopの特徴は以下の通りです。

  • カラー表示: CPU、メモリがバーグラフで視覚的に表示される
  • ツリー表示: プロセスの親子関係をツリー形式で表示(F5キー)
  • スクロール: 矢印キーでプロセス一覧をスクロールできる
  • 検索: F3キーでプロセス名を検索できる
  • フィルタ: F4キーでフィルタリングできる
項目 top htop
表示 モノクロ カラフル
操作性 キーボードのみ マウス対応
ツリー表示 なし あり
スクロール 限定的 自由
標準搭載 はい いいえ(要インストール)

8.7.4 freeでメモリ使用量確認

[実行ユーザー: 一般ユーザー]

$ free -h
               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       1.4Gi       1.2Gi       9.0Mi       1.2Gi       2.1Gi
Swap:          2.0Gi          0B       2.0Gi

各項目の意味

  • total: 物理メモリの総量
  • used: 使用中のメモリ
  • free: 完全に未使用のメモリ
  • shared: 共有メモリ
  • buff/cache: バッファ/キャッシュとして使用中
  • available: 実際に利用可能なメモリ

💡 重要: Linuxはメモリを積極的にキャッシュとして使います。freeが小さくても、availableが十分にあれば問題ありません。availableを見ることが重要です。

8.7.5 dfでディスク使用量確認

第4章でも学んだdfコマンドの復習です。

[実行ユーザー: 一般ユーザー]

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        50G   22G   28G  44% /
/dev/sda2       960M  224M  736M  24% /boot
/dev/sda1       599M  7.0M  592M   2% /boot/efi

# ファイルシステムタイプも表示
$ df -hT
Filesystem     Type   Size  Used Avail Use% Mounted on
/dev/sda3      xfs     50G   22G   28G  44% /
/dev/sda2      xfs    960M  224M  736M  24% /boot
/dev/sda1      vfat   599M  7.0M  592M   2% /boot/efi

8.7.6 uptimeでシステム負荷確認

uptimeは、システムの稼働時間とロードアベレージを表示します。

[実行ユーザー: 一般ユーザー]

$ uptime
 14:30:00 up 2 days,  3:45,  2 users,  load average: 0.15, 0.10, 0.05

ロードアベレージの読み方

ロードアベレージは、実行待ちのプロセス数の平均値です。3つの数値は、1分間、5分間、15分間の平均を表します。

  • ロードアベレージ < CPUコア数: 余裕がある
  • ロードアベレージ = CPUコア数: ちょうど100%使用
  • ロードアベレージ > CPUコア数: 過負荷(処理待ちが発生)

CPUコア数の確認方法は以下の通りです。

[実行ユーザー: 一般ユーザー]

$ nproc
2

# または
$ grep -c processor /proc/cpuinfo
2

2コアのサーバーでロードアベレージが2.0なら「ちょうど100%使用」、4.0なら「200%の過負荷」となります。

8.8 プロセス管理

問題のあるプロセスを特定し、必要に応じて終了させる方法を学びます。

8.8.1 プロセスとは

プロセスとは、実行中のプログラムのことです。各プロセスには一意のPID(Process ID)が割り当てられます。

  • プログラムをメモリに読み込んで実行したものがプロセス
  • 1つのプログラムから複数のプロセスが起動することもある
  • プロセスには親子関係がある(親プロセスが子プロセスを生成)

8.8.2 psコマンドでプロセス一覧

psは、現在実行中のプロセスを表示するコマンドです。

ps aux(BSD形式)

[実行ユーザー: 一般ユーザー]

$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.2 171234  9876 ?        Ss   Jan13   0:05 /usr/lib/systemd/systemd
root           2  0.0  0.0      0     0 ?        S    Jan13   0:00 [kthreadd]
...
root        1234  2.0  0.3 456789 12345 ?        Ss   14:25   0:15 /usr/sbin/httpd -DFOREGROUND
apache      1235  0.5  0.2 458901 10234 ?        S    14:25   0:03 /usr/sbin/httpd -DFOREGROUND
developer   5678  0.0  0.1  12345  3456 pts/0    R+   14:30   0:00 ps aux

ps -ef(System V形式)

[実行ユーザー: 一般ユーザー]

$ ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 Jan13 ?        00:00:05 /usr/lib/systemd/systemd
root           2       0  0 Jan13 ?        00:00:00 [kthreadd]
...
root        1234       1  2 14:25 ?        00:00:15 /usr/sbin/httpd -DFOREGROUND
apache      1235    1234  0 14:25 ?        00:00:03 /usr/sbin/httpd -DFOREGROUND

各列の意味(ps aux)

意味
USER プロセスの所有者
PID プロセスID
%CPU CPU使用率
%MEM メモリ使用率
VSZ 仮想メモリサイズ
RSS 実際のメモリ使用量
TTY 端末(?はデーモン)
STAT プロセスの状態
START 開始時刻
TIME CPU時間
COMMAND 実行コマンド

よく使うパターン

[実行ユーザー: 一般ユーザー]

# 特定のプロセスを検索
$ ps aux | grep httpd
root        1234  2.0  0.3 456789 12345 ?        Ss   14:25   0:15 /usr/sbin/httpd -DFOREGROUND
apache      1235  0.5  0.2 458901 10234 ?        S    14:25   0:03 /usr/sbin/httpd -DFOREGROUND
developer   5679  0.0  0.0  12345  1234 pts/0    S+   14:31   0:00 grep --color=auto httpd

# grepコマンド自身を除外
$ ps aux | grep [h]ttpd
root        1234  2.0  0.3 456789 12345 ?        Ss   14:25   0:15 /usr/sbin/httpd -DFOREGROUND
apache      1235  0.5  0.2 458901 10234 ?        S    14:25   0:03 /usr/sbin/httpd -DFOREGROUND

8.8.3 pgrepで名前からプロセス検索

pgrepは、プロセス名からPIDを検索するコマンドです。

[実行ユーザー: 一般ユーザー]

# プロセス名でPIDを検索
$ pgrep httpd
1234
1235
1236
1237
1238

# 詳細情報付きで表示
$ pgrep -a httpd
1234 /usr/sbin/httpd -DFOREGROUND
1235 /usr/sbin/httpd -DFOREGROUND
...

# ユーザー指定
$ pgrep -u apache httpd
1235
1236
1237
1238

8.8.4 killでプロセス終了

killは、プロセスにシグナルを送信するコマンドです。

主なシグナル

シグナル 番号 意味 用途
SIGTERM 15 終了要求 通常の終了(デフォルト)
SIGKILL 9 強制終了 最終手段
SIGHUP 1 ハングアップ 設定再読み込み
SIGINT 2 割込み Ctrl+Cと同等

[実行ユーザー: 一般ユーザー(sudo使用)]

# 通常の終了(SIGTERM、デフォルト)
$ sudo kill 1234

# または明示的に
$ sudo kill -15 1234
$ sudo kill -SIGTERM 1234

# 強制終了(SIGKILL、最終手段)
$ sudo kill -9 1234
$ sudo kill -SIGKILL 1234

SIGTERMとSIGKILLの違い

  • SIGTERM(-15): プロセスに「終了してください」と依頼する。プロセスは終了処理(ファイルのクローズ、一時ファイルの削除など)を行ってから終了できる
  • SIGKILL(-9): プロセスを即座に強制終了する。プロセスは終了処理を行えない。データ損失やリソースリークの可能性がある

🚨 注意: kill -9は最終手段です。まずkill(SIGTERM)を試し、それでも終了しない場合にのみkill -9を使ってください。特にデータベースなどは、強制終了するとデータが壊れる可能性があります。

8.8.5 killall, pkillの使い方

プロセス名を指定して終了させることもできます。

killall – 名前でプロセスを終了

[実行ユーザー: 一般ユーザー(sudo使用)]

# httpdという名前のプロセスをすべて終了
$ sudo killall httpd

# 強制終了
$ sudo killall -9 httpd

pkill – パターンマッチでプロセスを終了

[実行ユーザー: 一般ユーザー(sudo使用)]

# httpdを含むプロセスを終了
$ sudo pkill httpd

# 特定ユーザーのプロセスを終了
$ sudo pkill -u apache

# 強制終了
$ sudo pkill -9 httpd

⚠️ 注意: killallpkillは、意図しないプロセスまで終了させてしまう可能性があります。本番環境では、まずpgrepで対象を確認してから実行しましょう。

8.9 高度なトラブルシューティングツール

より深い調査が必要な場合に使うツールを紹介します。これらは「存在を知っておく」レベルで構いません。

8.9.1 lsof – ファイルを開いているプロセスを特定

lsof(List Open Files)は、開いているファイルとそのプロセスを表示します。

インストール

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo dnf install lsof

使用例

[実行ユーザー: 一般ユーザー(sudo使用)]

# 特定のポートを使っているプロセスを特定
$ sudo lsof -i :80
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd    1234   root    4u  IPv6  12345      0t0  TCP *:http (LISTEN)
httpd    1235 apache    4u  IPv6  12345      0t0  TCP *:http (LISTEN)

# 特定のファイルを開いているプロセスを特定
$ sudo lsof /var/log/messages
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
rsyslogd 1234 root    5w   REG  253,0   123456 123456 /var/log/messages

# 特定のプロセスが開いているファイル一覧
$ sudo lsof -p 1234

よくある使用場面

  • 「Address already in use」エラーの原因特定
  • 削除できないファイルの調査(プロセスが開いている)
  • ネットワーク接続の調査

8.9.2 strace – システムコールのトレース

straceは、プロセスが実行するシステムコール(OSへの呼び出し)を追跡します。

インストール

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo dnf install strace

使用例

[実行ユーザー: 一般ユーザー(sudo使用)]

# コマンドの実行をトレース
$ strace ls /tmp
execve("/usr/bin/ls", ["ls", "/tmp"], 0x7fff... /* 23 vars */) = 0
...
openat(AT_FDCWD, "/tmp", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
...

# 実行中のプロセスにアタッチ
$ sudo strace -p 1234

# ファイルアクセスのみ表示
$ strace -e open,openat,read,write ls /tmp

straceは非常に強力ですが、出力が大量になるため、フィルタリングオプションを使いこなす必要があります。「プログラムがどのファイルを読んでいるか」「なぜエラーになるか」を調査するときに有用です。

8.9.3 tcpdump – ネットワークパケットキャプチャ

tcpdumpは、ネットワークパケットをキャプチャして表示します。

インストール

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo dnf install tcpdump

使用例

[実行ユーザー: 一般ユーザー(sudo使用)]

# 特定インターフェースのトラフィックをキャプチャ
$ sudo tcpdump -i enp0s3

# 特定ポートのトラフィック
$ sudo tcpdump -i enp0s3 port 80

# 特定ホストとの通信
$ sudo tcpdump -i enp0s3 host 192.168.1.50

# ファイルに保存(後でWiresharkで分析可能)
$ sudo tcpdump -i enp0s3 -w /tmp/capture.pcap

tcpdumpは、ネットワーク通信の詳細な調査に使います。「パケットは届いているか」「何が送受信されているか」を確認できます。

8.9.4 dmesg – カーネルメッセージ

dmesgは、カーネルのリングバッファに記録されたメッセージを表示します。

[実行ユーザー: 一般ユーザー(sudo使用)]

# 全メッセージ表示
$ sudo dmesg

# 人間が読みやすい時刻形式で表示
$ sudo dmesg -T

# エラーと警告のみ
$ sudo dmesg -T --level=err,warn

# リアルタイム監視
$ sudo dmesg -Tw

ハードウェア関連の問題(ディスクエラー、ネットワークインターフェースの問題など)を調査するときに使います。

8.9.5 パフォーマンス分析ツール

より詳細なパフォーマンス分析には、sysstatパッケージのツール群が使えます。

インストール

[実行ユーザー: 一般ユーザー(sudo使用)]

$ sudo dnf install sysstat
$ sudo systemctl enable --now sysstat

sar – システム活動レポート

[実行ユーザー: 一般ユーザー]

# CPU使用率の履歴
$ sar -u

# メモリ使用率の履歴
$ sar -r

# ディスクI/Oの履歴
$ sar -d

iostat – ディスクI/O統計

[実行ユーザー: 一般ユーザー]

$ iostat -x 1
Linux 6.12.0-1.el10.x86_64 (server1) 	01/15/2026 	_x86_64_	(2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.34    0.00    1.02    0.15    0.00   96.49

Device            r/s     w/s     rkB/s     wkB/s   await  %util
sda              5.23   12.45     84.56    198.76    2.34   1.23

vmstat – 仮想メモリ統計

[実行ユーザー: 一般ユーザー]

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 1234567  12345 567890    0    0    12    34  123  456  2  1 97  0  0
 0  0      0 1234567  12345 567890    0    0     0    12  100  234  1  0 99  0  0

これらのツールは、パフォーマンス問題の詳細な分析に使います。本ガイドでは紹介にとどめますが、「こういうツールがある」と覚えておくと、必要なときに調べて使えます。

8.10 実践的なトラブルシューティング演習

学んだ内容を実践してみましょう。

8.10.1 意図的に問題を起こして解決する

学習環境(VPS)で、意図的に問題を起こして解決する練習をしましょう。

演習1: サービス起動失敗

[実行ユーザー: 一般ユーザー(sudo使用)]

# 1. httpdの設定ファイルを意図的に壊す
$ sudo cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak
$ echo "InvalidDirective" | sudo tee -a /etc/httpd/conf/httpd.conf

# 2. 起動を試みる
$ sudo systemctl restart httpd
# → 失敗する

# 3. ログを確認して原因を特定
$ journalctl -u httpd -e

# 4. 設定を修復
$ sudo cp /etc/httpd/conf/httpd.conf.bak /etc/httpd/conf/httpd.conf

# 5. 起動確認
$ sudo systemctl start httpd
$ systemctl status httpd

演習2: ディスク容量不足のシミュレーション

[実行ユーザー: 一般ユーザー]

# 1. 大きなファイルを作成(学習環境でのみ実行)
$ dd if=/dev/zero of=~/bigfile bs=1M count=500

# 2. ディスク容量を確認
$ df -h

# 3. 原因を特定
$ du -sh ~/*

# 4. ファイルを削除
$ rm ~/bigfile

# 5. 容量を確認
$ df -h

8.10.2 ログから原因を特定する思考プロセス

以下のログを見て、何が起きているか考えてみましょう。

Jan 15 14:30:00 server1 sshd[5678]: Failed password for invalid user admin from 203.0.113.50 port 54321 ssh2
Jan 15 14:30:05 server1 sshd[5679]: Failed password for invalid user admin from 203.0.113.50 port 54322 ssh2
Jan 15 14:30:10 server1 sshd[5680]: Failed password for invalid user admin from 203.0.113.50 port 54323 ssh2
Jan 15 14:30:15 server1 sshd[5681]: Failed password for invalid user root from 203.0.113.50 port 54324 ssh2
Jan 15 14:30:20 server1 sshd[5682]: Failed password for invalid user test from 203.0.113.50 port 54325 ssh2

分析

  • 同じIPアドレス(203.0.113.50)から5秒間隔でアクセス
  • 存在しないユーザー(admin, root, test)でログイン試行
  • すべて「Failed password」(パスワード認証失敗)

結論

これはブルートフォース攻撃(総当たり攻撃)の兆候です。対策としては、fail2banの導入、パスワード認証の無効化(公開鍵認証のみ)、IPアドレスのブロックなどが考えられます。

8.10.3 問題解決後の検証方法

問題を解決したら、必ず以下を確認します。

  1. サービスの状態: systemctl statusでactive (running)を確認
  2. ログのエラー: journalctl -p errでエラーがないことを確認
  3. 機能テスト: 実際にサービスが動作することを確認(curlでアクセスなど)
  4. リソース: CPU、メモリ、ディスクが正常範囲内であることを確認

8.10.4 再発防止策の検討

問題が解決したら、同じ問題が再発しないよう対策を講じます。

  • 設定ミス: 変更前のバックアップ、構文チェックの習慣化
  • ディスク容量: ログローテーション設定、監視の追加
  • ネットワーク: 冗長化、監視の追加
  • セキュリティ: fail2banの導入、定期的なログ監視

8.10.5 ドキュメント化の重要性

発生した問題と解決策は必ず記録しておきましょう。

記録すべき内容

  • 発生日時
  • 症状(何が起きたか)
  • 影響範囲(どのサービスに影響したか)
  • 原因
  • 解決手順
  • 再発防止策

この記録は、将来同じ問題が発生したときに役立ちます。また、チームでの知識共有にも重要です。


【コラム7】ログを読まずに5時間無駄にした話

入社2年目の頃の話です。

ある日の午後、先輩から「開発環境のWebアプリが動かないんだけど、見てくれない?」と頼まれました。

「任せてください!」と意気込んで調査を開始。まず、アプリケーションのソースコードを確認しました。設定ファイルも見直しました。データベースへの接続も試しました。

2時間経過。原因がわかりません。

「もしかしてフレームワークのバグかも」と思い、GitHubのIssuesを検索。似たような問題を探しましたが、見つかりません。

4時間経過。焦りが出てきました。

「ネットワークの問題かも」と思い、ping、traceroute、curlを駆使して調査。問題は見つかりません。

5時間が過ぎた頃、たまたま通りかかった先輩が「どう?」と声をかけてきました。

「全然わからないんです。コードも設定も問題なさそうなのに…」

先輩は一言。「ログ見た?

…見てませんでした。

$ journalctl -u myapp -e
Jan 15 10:00:00 devserver myapp[1234]: ERROR: Configuration file not found: /etc/myapp/config.yml
Jan 15 10:00:00 devserver myapp[1234]: Please create the configuration file or set MYAPP_CONFIG environment variable.

設定ファイルのパスが変わっていて、ファイルが見つからなかったのです。

設定ファイルを正しい場所にコピーして、サービスを再起動。1分で解決しました。

5時間かけて調べたことは、すべてログの1行目に書いてあったのです。

先輩は笑いながら言いました。「困ったら、まずログ。これ、鉄則だから」

それ以来、私は何か問題が起きたら、まずjournalctlを叩くようになりました。この習慣のおかげで、無駄な時間を過ごすことは激減しました。

教訓:

  • 問題が起きたら、まずログを見る
  • 思い込みで調査しない(「コードの問題だ」と決めつけない)
  • 基本に立ち返る(複雑に考えすぎない)

5時間という「授業料」は高くつきましたが、二度と忘れない教訓になりました。


章末まとめ

この章では、ログ管理とトラブルシューティングの基礎を学びました。

学んだこと

  • ログの重要性: 障害対応の90%はログから始まる。「まずログを見る」を習慣に
  • ログファイルの構成: /var/log/配下の主要なログファイルと用途
  • journalctlの実践的な使い方: 時間範囲、優先度、サービスでのフィルタリング、grepとの組み合わせ
  • トラブルシューティングの流れ: 事象の特定 → 情報収集 → 仮説 → 検証 → 対処 → 確認 → 再発防止
  • ケーススタディ: サービス起動失敗、ネットワーク問題、ディスク容量不足の解決方法
  • システム監視: top/htop、free、df、uptimeの使い方
  • プロセス管理: ps、pgrep、kill、killall、pkillの使い方
  • 高度なツール: lsof、strace、tcpdump、dmesg、sysstatの存在

重要なコマンド

用途 コマンド
ログ確認(基本) journalctl -u サービス名 -e
ログ確認(時間指定) journalctl --since "1 hour ago"
ログ確認(エラーのみ) journalctl -p err
リアルタイム監視 journalctl -f
システム負荷 tophtopuptime
メモリ確認 free -h
ディスク確認 df -hdu -sh
プロセス一覧 ps auxpgrep
プロセス終了 kill PIDkill -9 PID

練習問題

問題1: journalctlで、httpdサービスの直近1時間のエラー以上のログを確認するコマンドを書いてください。

解答を表示
$ journalctl -u httpd --since "1 hour ago" -p err

-u httpdでサービス指定、--since "1 hour ago"で時間範囲指定、-p errでエラー以上を指定します。

問題2: topコマンドの出力で「load average: 4.50, 3.20, 2.10」と表示されています。このサーバーは2コアCPUです。現在の負荷状況を説明してください。

解答を表示

ロードアベレージが4.50(直近1分平均)で、CPUコア数(2)の2倍以上あるため、過負荷状態です。実行待ちのプロセスが常に存在し、処理が遅延している状態です。5分平均(3.20)、15分平均(2.10)を見ると、負荷が増加傾向にあることもわかります。

問題3: ディスク容量不足が発生しました。原因を特定するためのコマンドを、実行順に3つ挙げてください。

解答を表示
# 1. ディスク全体の使用状況を確認
$ df -h

# 2. どのディレクトリが容量を使っているか確認
$ sudo du -sh /* | sort -rh | head -10

# 3. さらに詳細を特定(例: /varが大きい場合)
$ sudo du -sh /var/* | sort -rh | head -10

問題4: プロセスを安全に終了させる場合、まず何のシグナルを送るべきですか?また、それでも終了しない場合に使うシグナルは何ですか?理由も含めて説明してください。

解答を表示

最初に送るシグナル: SIGTERM(15)

理由: プロセスに終了を依頼し、正常な終了処理(ファイルのクローズ、一時ファイルの削除など)を行う機会を与えるため。

$ kill 1234        # または
$ kill -15 1234

それでも終了しない場合: SIGKILL(9)

理由: SIGTERMを無視するプロセスを強制終了するため。ただし、終了処理が行われないため、データ損失やリソースリークの可能性がある。最終手段として使用する。

$ kill -9 1234

問題5: サービスが起動しないというトラブルが発生しました。調査手順を5つのステップで説明してください。

解答を表示
  1. サービスの状態確認:
    $ systemctl status サービス名
  2. ログでエラー内容を確認:
    $ journalctl -u サービス名 -xe
  3. 設定ファイルの構文チェック:(サービスによる)
    $ sudo apachectl configtest  # Apacheの場合
    $ sudo nginx -t              # Nginxの場合
  4. パーミッションとSELinuxの確認:
    $ ls -la /path/to/config
    $ sudo ausearch -m AVC -ts recent
  5. ポート競合の確認:
    $ sudo ss -tlnp | grep :ポート番号

問題6: 以下のfreeコマンドの出力を見て、このサーバーのメモリ状態を評価してください。追加のメモリが必要かどうかも判断してください。

               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       3.2Gi       100Mi       50Mi       500Mi       400Mi
Swap:          2.0Gi       1.5Gi       500Mi
解答を表示

状態: メモリが逼迫しています。

  • 物理メモリ3.8GBのうち、availableが400MBしかない
  • スワップが1.5GB使用されている(物理メモリが足りず、ディスクに退避している)

評価:

  • availableが総メモリの10%程度しかなく、余裕がない
  • スワップが大量に使用されているため、パフォーマンスが低下している可能性が高い

判断: メモリの増設を検討すべき状態です。または、メモリを大量に消費しているプロセスを特定し、チューニングや分散を検討します。


次章への橋渡し

この章では、問題が発生したときの対処方法を学びました。しかし、本当に重要なのは問題が発生しないように予防することです。

次の第9章「バックアップと運用の基礎」では、以下を学びます。

  • バックアップの重要性: データ損失からの復旧
  • バックアップ戦略: フルバックアップ、増分バックアップ
  • tarとrsync: バックアップツールの使い方
  • ログローテーション: ログファイルの適切な管理
  • システムメンテナンス: 定期的な運用作業
  • ドキュメンテーション: 運用手順書の作成

トラブルシューティングができるようになった今、次は「トラブルを予防する運用」を学びましょう。

前の記事
次の記事