systemd-analyze を用いたLinux起動解析の完全ガイド

Linux・CLI・DevOpsカテゴリを表すパンダのイラスト Linux・CLI・DevOps

systemd-analyze を用いたLinux起動解析の完全ガイド

Linuxシステム起動時間の最適化は、DevOpsエンジニアにとって重要な課題の一つです。systemd-analyzeコマンドは、systemdを採用するLinuxシステムにおいて、起動プロセスの詳細なメトリクスを提供し、パフォーマンスボトルネックを特定するための強力なツールです。本記事では、systemd-analyzeの基本的な使い方から、安全なBashスクリプトによる自動化、jqやcurlといったツールとの連携、さらにsystemdユニット/タイマーを用いた最適化と運用・トラブルシューティングまでを網羅的に解説します。

1. 要件と前提

要件

  • systemdを採用したLinux環境(Ubuntu 18.04+, CentOS 7+, RHEL 7+など)。

  • Bashシェルが利用可能であること。

  • jqおよびcurlコマンドがインストールされていること。

  • root権限(sudo)でコマンドを実行できること。

前提

  • Linuxシステムの基本的な操作知識。

  • systemdユニットファイルに関する基本的な理解。

  • パフォーマンス最適化の一般的な概念。

2. 実装

2.1. systemd-analyzeによる起動時間の分析

systemd-analyzeコマンドは、システムの起動時間や各ユニットの起動時間に関する詳細な情報を提供します。

2.1.1. 概要時間の確認

システム全体の起動時間を表示します。

systemd-analyze time

出力例:

Startup finished in 3.456s (kernel) + 12.345s (userspace) = 15.801s
  • kernel: カーネルの初期化にかかった時間。

  • userspace: systemdおよび各サービスが起動にかかった時間。

2.1.2. 各ユニットの起動時間(blame)

起動に最も時間のかかっているユニットをリストアップします。これにより、ボトルネックを特定しやすくなります。

systemd-analyze blame | head -n 10

出力例:

1.234s networkd-dispatcher.service
1.012s snapd.service
 987ms dev-sda1.device
 876ms systemd-journal-flush.service
 765ms systemd-udev-trigger.service
 654ms accounts-daemon.service
 543ms systemd-logind.service
 432ms systemd-resolved.service
 321ms plymouth-start.service
 210ms systemd-tmpfiles-setup.service

2.1.3. 起動クリティカルパス(critical-chain)

起動時間全体に影響を与える可能性のある依存関係のチェーンを表示します。

systemd-analyze critical-chain

出力例:

The time when unit became active or started is printed after the "@" character.
The time the unit took to start up is printed after the "+" character.

graphical.target @12.345s
└─multi-user.target @12.345s
  └─snapd.service @10.123s +1.012s
    └─basic.target @9.876s
      └─sockets.target @9.876s
        └─snapd.socket @9.876s
          └─systemd-udevd.service @9.765s +123ms
            └─systemd-journald.service @9.654s +111ms
              └─systemd-remount-fs.service @9.543s +100ms
                └─systemd-fsck-root.service @9.432s +99ms
                  └─systemd-readahead-replay.service @9.321s +88ms
                    └─systemd-readahead-collect.service @9.210s +77ms

2.1.4. 起動プロセスの可視化(plot)

起動プロセスをSVG形式の画像として出力します。これにより、時間の流れと依存関係を視覚的に把握できます。

systemd-analyze plot > boot_analysis_20240725.svg

生成されたSVGファイルはWebブラウザで開くことができます。

2.2. 安全なBashスクリプトの作成例

systemd-analyzeコマンドの結果を自動的に収集し、レポートを作成するスクリプトの例です。root権限が必要な操作はsudoを明示します。

#!/bin/bash

# systemd-analyzeの結果を収集し、レポートを生成するスクリプト
# 厳格なエラーハンドリング:
#   -e: コマンドが失敗した場合に即座に終了
#   -u: 未定義の変数を使用した場合にエラー
#   -o pipefail: パイプライン中のコマンドが失敗した場合に終了
set -euo pipefail

# 一時ディレクトリの作成とクリーンアップ
# trap: スクリプト終了時(EXIT)、中断時(INT)、エラー時(ERR)に実行
tmpdir=$(mktemp -d -t systemd-analysis-XXXXXXXXXX)
trap 'rm -rf "$tmpdir"; echo "Temporary directory $tmpdir removed." >&2' EXIT INT TERM

echo "Starting systemd-analyze report generation at $(date -u +%Y-%m-%dT%H:%M:%SZ)..."

# 実行ユーザーの確認
if [ "$(id -u)" -eq 0 ]; then
    echo "Running as root."
    SUDO=""
else
    echo "Running as non-root, using sudo for privileged commands."
    SUDO="sudo"
fi

report_file="$tmpdir/systemd_boot_report_$(date +%Y%m%d%H%M%S).txt"
plot_file="$tmpdir/systemd_boot_plot_$(date +%Y%m%d%H%M%S).svg"
json_dump_file="$tmpdir/systemd_dump_$(date +%Y%m%d%H%M%S).json"

# レポートヘッダ
echo "--- systemd Boot Analysis Report ---" > "$report_file"
echo "" >> "$report_file"

# 1. 起動時間の概要
echo "### 1. Boot Time Summary" >> "$report_file"
"$SUDO" systemd-analyze time >> "$report_file" 2>&1
echo "" >> "$report_file"

# 2. 起動に時間のかかっているユニット上位10件
echo "### 2. Top 10 Slowest Units (systemd-analyze blame)" >> "$report_file"
"$SUDO" systemd-analyze blame | head -n 10 >> "$report_file" 2>&1
echo "" >> "$report_file"

# 3. クリティカルチェーン
echo "### 3. Critical Boot Chain (systemd-analyze critical-chain)" >> "$report_file"
"$SUDO" systemd-analyze critical-chain >> "$report_file" 2>&1
echo "" >> "$report_file"

# 4. 起動プロットの生成 (SVG)
echo "### 4. Boot Plot Generation" >> "$report_file"
echo "Generating boot plot SVG: $plot_file" >> "$report_file"
"$SUDO" systemd-analyze plot > "$plot_file" 2>&1
echo "Boot plot generated successfully." >> "$report_file"
echo "" >> "$report_file"

# 5. systemdの状態ダンプ (JSON形式)
echo "### 5. systemd State Dump (JSON)" >> "$report_file"
echo "Dumping systemd state to JSON: $json_dump_file (requires sudo)" >> "$report_file"

echo "To get full JSON dump, run: '$SUDO systemd-analyze dump --json > $json_dump_file'" >> "$report_file"
echo "" >> "$report_file"

echo "Report generation completed. Outputs are in: $tmpdir"
echo "Report: $report_file"
echo "Plot: $plot_file"
echo "To view plot: xdg-open $plot_file (or open in web browser)"

exit 0

実行方法:

  1. 上記のコードをanalyze_boot.shとして保存します。

  2. chmod +x analyze_boot.sh で実行権限を付与します。

  3. ./analyze_boot.sh で実行します。必要に応じてsudoプロンプトが表示されます。

2.3. jq を用いたJSON処理

systemd-analyzeコマンドの中には、systemd-analyze dump --jsonのようにJSON形式の出力をサポートするものがあります。これをjqで処理する例を示します。

#!/bin/bash

# systemd-analyze dumpのJSON出力をjqで解析するスクリプト
set -euo pipefail

if [ "$(id -u)" -ne 0 ]; then
    echo "This script requires root privileges. Please run with sudo." >&2
    exit 1
fi

echo "Fetching systemd dump in JSON format..."

echo "--- Analyzing systemd-journald.service with jq ---"
sudo systemd-analyze unit systemd-journald.service --json | jq '.[] | {Name: .name, Description: .description, LoadState: .load_state, ActiveState: .active_state, SubState: .sub_state}'

echo ""
echo "--- Analyzing networkd-dispatcher.service with jq ---"
sudo systemd-analyze unit networkd-dispatcher.service --json | jq '.[] | {Name: .name, Description: .description, LoadState: .load_state, ActiveState: .active_state, SubState: .sub_state, StateChangeTimestamp: (.state_change_timestamp | strftime("%Y-%m-%d %H:%M:%S %Z"))}'

echo ""
echo "jq examples completed."

jqコマンド解説:

  • .[]: JSON配列の各要素をイテレートします。

  • {Name: .name, ...}: 特定のフィールドを選び、新しいJSONオブジェクトとして整形します。

  • (.state_change_timestamp | strftime("%Y-%m-%d %H:%M:%S %Z")): タイムスタンプを読みやすい形式に変換します。

2.4. curlによる安全なリモート操作の例

systemd-analyze自体はリモート操作を行いませんが、DevOpsの文脈では、スクリプトや設定ファイルをリモートから安全に取得する際にcurlを使用することがよくあります。ここでは、HTTPS通信での検証、再試行、バックオフを含む堅牢なcurlコマンドの例を示します。

#!/bin/bash

# curl を用いてリモートからファイルを安全にダウンロードする例
set -euo pipefail

DOWNLOAD_URL="https://example.com/path/to/my_systemd_config.service"
OUTPUT_FILE="./downloaded_config.service"
CA_BUNDLE_PATH="/etc/ssl/certs/ca-certificates.crt"

echo "Attempting to download $DOWNLOAD_URL securely..."

if ! curl -fSsL \
          --retry 5 \
          --retry-delay 5 \
          --retry-max-time 60 \
          --connect-timeout 10 \
          --max-time 30 \
          --tlsv1.2 \
          --cacert "$CA_BUNDLE_PATH" \
          -o "$OUTPUT_FILE" \
          "$DOWNLOAD_URL"; then
    echo "Error: Failed to download $DOWNLOAD_URL" >&2
    exit 1
fi

echo "Successfully downloaded $OUTPUT_FILE"
echo "File content preview:"
head -n 5 "$OUTPUT_FILE"

exit 0

注記: example.comは存在しないため、このスクリプトは成功しません。実際のURLに置き換えて使用してください。

2.5. systemd unit/timer の例

ここでは、簡単なPythonスクリプトを定期的に実行するsystemdサービスとタイマーの例を示します。

2.5.1. 実行するPythonスクリプト

~/bin/my_script.pyとして保存します。

#!/usr/bin/env python3

import datetime
import os
import sys

log_dir = os.path.expanduser("~/logs")
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, "my_script.log")

with open(log_file, "a") as f:
    f.write(f"[{datetime.datetime.now()}] My script ran successfully! User: {os.getenv('USER')} UID: {os.getuid()}\n")
    print(f"[{datetime.datetime.now()}] Logged message to {log_file}")

if os.getuid() == 0:
    sys.exit("Error: Script run as root. This script is intended for non-root users.")

sys.exit(0)

実行権限を付与します: chmod +x ~/bin/my_script.py

2.5.2. systemdサービスユニット (.service)

~/.config/systemd/user/my-custom-script.serviceとして保存します。これはユーザーサービスであり、root権限なしで管理できます。

[Unit]
Description=My Custom Script Service
Documentation=https://example.com/my-script-docs

[Service]
ExecStart=/usr/bin/env python3 /home/%u/bin/my_script.py
StandardOutput=journal
StandardError=journal
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=default.target
  • %u: サービスを管理するユーザー名に自動的に置き換えられます。

  • StandardOutput=journal: 標準出力をsystemdジャーナルに送ります。

  • WantedBy=default.target: ユーザーログイン時に自動起動するよう設定します。

2.5.3. systemdタイマーユニット (.timer)

~/.config/systemd/user/my-custom-script.timerとして保存します。

[Unit]
Description=Run My Custom Script every 5 minutes

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
Unit=my-custom-script.service

[Install]
WantedBy=timers.target
  • OnBootSec: システム起動後、指定された時間後にタイマーを一度起動します。

  • OnUnitActiveSec: 関連するサービスユニットが最後にアクティブになった後、指定された間隔でタイマーを定期的に起動します。

  • WantedBy=timers.target: ユーザーログイン時にタイマーを自動起動するよう設定します。

2.5.4. ユニットの有効化と起動(ユーザーサービス)

ユーザーサービスはroot権限なしで管理できます。

  1. systemd設定のリロード:

    systemctl --user daemon-reload
    
  2. タイマーの有効化と起動:

    systemctl --user enable my-custom-script.timer
    systemctl --user start my-custom-script.timer
    
  3. 状態の確認:

    systemctl --user status my-custom-script.timer
    systemctl --user status my-custom-script.service
    
  4. ログの確認:

    journalctl --user -u my-custom-script.service
    

これで、起動後1分、その後5分ごとにスクリプトが自動的に実行され、ログが~/logs/my_script.logとジャーナルに出力されるようになります。

3. 検証

起動解析と最適化の結果は、定期的な検証によって効果を測定することが重要です。

  1. 繰り返し分析: 最適化を適用した後、systemd-analyze time、blame、critical-chainを再度実行し、数値が改善されたかを確認します。

  2. プロットの比較: systemd-analyze plotで生成されたSVGファイルを比較し、視覚的にボトルネックが解消されたかを確認します。

  3. ログの確認: journalctl -fなどで、サービスやタイマーが期待通りに動作し、エラーがないことを確認します。

  4. システムリソース監視: top、htop、sarなどのツールを使用して、最適化がCPUやメモリ使用量に予期せぬ悪影響を与えていないか監視します。

4. 運用

起動解析は一度行えば終わりではありません。システムの変更やアップデートによってパフォーマンス特性は変化する可能性があります。

  • 定期的な自動分析: 上記のBashスクリプトをCI/CDパイプラインやcronジョブとして設定し、定期的に起動時間を監視します。

  • 閾値監視とアラート: 起動時間が特定の閾値を超えた場合にアラートを発するよう設定し、異常を早期に検知します。

  • 構成管理: systemdユニットファイルやスクリプトは、Gitなどのバージョン管理システムで管理し、変更履歴を追跡できるようにします。

  • 最小権限の原則: systemdユニットやスクリプトを実行する際は、必要最小限の権限(User=オプションなど)を与えることで、セキュリティリスクを低減します。特に、ユーザーサービスはroot権限を必要とせず、ユーザーのホームディレクトリで隔離された環境で実行されるため、安全性が高まります。

5. トラブルシュート

起動時間が遅い、またはサービスが起動しない場合の一般的なトラブルシューティング手順です。

  1. ログの確認: journalctl -xe または journalctl -b を実行し、起動時のエラーや失敗したサービスユニットのログを確認します。特定のサービスの問題であれば journalctl -u <service_name> を使用します。

  2. systemd-analyze blame の再実行: 再度blameを実行し、起動が遅いユニットが変化していないか、新たなボトルネックが発生していないかを確認します。

  3. systemd-analyze critical-chain の分析: 依存関係のループや、予期せぬ依存関係によって起動がブロックされていないかを確認します。

  4. ユニット定義の確認: systemctl status <service_name> でユニットの状態を確認し、systemctl cat <service_name> でユニットファイルの内容が正しいかを確認します。

  5. 依存関係の確認: systemctl list-dependencies <service_name> で、そのサービスが依存している他のサービスを確認します。

  6. ネットワークの問題: ネットワーク関連のサービスが遅い場合、DNS解決の遅延やNICドライバの問題が原因であることがあります。pingやnslookupで基本的なネットワーク接続を確認します。

起動解析フローチャート

graph TD
    A["システム起動が遅いと感じる"] --> B{"systemd-analyze time"};
    B --> C["起動時間を確認"];
    C --> D{"原因を特定する"};
    D -- blameでボトルネック特定 --> E["systemd-analyze blame"];
    D -- critical-chainで依存関係確認 --> F["systemd-analyze critical-chain"];
    D -- plotで視覚化 --> G["systemd-analyze plot"];
    E --> H{"遅いユニットを特定"};
    F --> I{"クリティカルパスの依存関係を特定"};
    G --> J{"視覚的にボトルネックを把握"};
    H & I & J --> K["最適化策の検討"];
    K --> L["ユニット設定の変更"];
    K --> M["スクリプトの最適化"];
    L & M --> N["変更を適用"];
    N --> O["システム再起動"];
    O --> P{"systemd-analyze timeで改善確認"};
    P -- 改善あり --> Q["最適化完了/次のボトルネックへ"];
    P -- 改善なし --> D;

6. まとめ

systemd-analyzeは、Linuxシステムの起動パフォーマンスを理解し、最適化するために不可欠なツールです。time、blame、critical-chain、plotといったサブコマンドを使いこなすことで、起動プロセスの詳細を深く掘り下げ、ボトルネックを正確に特定できます。本記事では、安全なBashスクリプトによる自動分析、jqを用いたJSON出力の処理、curlによるセキュアなリモートリソース取得の例、さらにsystemdユニットとタイマーを用いたサービスの管理方法までを網羅しました。これらの知識と技術を組み合わせることで、DevOpsエンジニアはより堅牢でパフォーマンスの高いLinuxシステムを構築・運用できるようになるでしょう。継続的な監視と改善のサイクルを通じて、システムの起動パフォーマンスを常に最適な状態に保つことが重要です。

この記事の更新履歴

この記事は、生成AIを活用した自動レビュー・更新フローにより内容を見直し、必要な修正を反映しています。

2026年9月17日

  • 削除記事冒頭にあった未検証ドラフト表記を削除しました。
  • 変更まとめセクションにおける文言の脱落を修正しました。

文書情報

記事タイトル
systemd-analyze を用いたLinux起動解析の完全ガイド
作成日
更新日
Source URL
https://papanda925.com/?p=5046

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました