【RHEL】独自のsystemdサービスの作成から管理まで

RHEL

今回は、RHEL系Linuxにおけるsystemdサービスの作成から管理方法まで、基礎から実践的な内容まで網羅的に解説します。

自作のスクリプトをサービス化したい、システム起動時に自動実行させたい、といった要望を持つシステム管理者の方に向けて、実務で役立つ知識を丁寧に説明していきます。

  1. systemdとは
    1. なぜサービス化が必要なのか
  2. systemdサービスの基礎知識
    1. ユニットファイルとは
    2. ユニットファイルの配置場所
  3. サービスユニットファイルの基本構造
    1. [Unit]セクション
    2. [Service]セクション
    3. [Install]セクション
  4. 実践例1: シンプルなシェルスクリプトのサービス化
    1. ステップ1: スクリプトの作成
    2. ステップ2: サービスユニットファイルの作成
    3. ステップ3: サービスの有効化と起動
  5. 実践例2: バックアップスクリプトの定期実行
    1. バックアップスクリプトの作成
    2. 方法1: 通常のサービスとして実行
    3. 方法2: systemdタイマーを使用
    4. cronとsystemdタイマーの違い
  6. 実践例3: 監視スクリプトのデーモン化
    1. 監視スクリプトの作成
    2. サービスファイルの作成
  7. サービスの基本操作コマンド
    1. サービスの起動
    2. サービスの停止
    3. サービスの再起動
    4. サービスの状態確認
    5. 自動起動の有効化
    6. 自動起動の無効化
    7. 有効化と同時に起動
    8. 全サービスの一覧表示
  8. ログの確認方法(journalctl)
    1. 特定のサービスのログを表示
    2. 最新のログをリアルタイムで表示
    3. 指定した行数のログを表示
    4. 日時を指定してログを表示
    5. 優先度を指定してログを表示
  9. トラブルシューティング
    1. ステップ1: 状態の確認
    2. ステップ2: ログの確認
    3. ステップ3: 設定ファイルの検証
    4. ステップ4: 実行権限の確認
    5. ステップ5: スクリプトの単体テスト
    6. よくあるエラーと対処法
  10. まとめ

systemdとは

systemdは、現代のLinuxシステムで広く採用されているシステム・サービスマネージャーです。RHEL 7以降、CentOS 7以降、そしてAlmaLinux、Rocky Linuxなどの主要なRHEL系ディストリビューションで標準的に使用されています。

従来のinitシステムに代わって登場したsystemdは、サービスの起動・停止・管理を統一的に行うことができ、並列起動による高速化やサービス間の依存関係管理など、多くの利点を持っています。

なぜサービス化が必要なのか

実務では、以下のような場面でスクリプトやアプリケーションをサービス化する必要が出てきます。

  • システム起動時に自動的にプログラムを実行したい
  • バックグラウンドで常時動作するプロセスを管理したい
  • 定期的にバックアップスクリプトを実行したい
  • サービスの起動・停止を標準化された方法で管理したい
  • プロセスが異常終了した際に自動再起動させたい

これらの要件を満たすために、systemdサービスの作成方法を理解することが重要です。

systemdサービスの基礎知識

ユニットファイルとは

systemdでは、サービスを「ユニット」という単位で管理します。ユニットファイルは、サービスの設定を記述したテキストファイルで、.serviceという拡張子を持ちます。

例えば、myapp.serviceというファイル名でサービスを定義します。

ユニットファイルの配置場所

ユニットファイルを配置する場所は主に2つあります。

1. /usr/lib/systemd/system/

  • システムにインストールされたパッケージが提供するサービスの配置場所
  • yumやdnfでインストールしたソフトウェアのサービスファイルがここに配置される
  • 基本的にパッケージ管理システムが管理する領域
2. /etc/systemd/system/

  • システム管理者が独自に作成・カスタマイズするサービスの配置場所
  • /usr/lib/systemd/system/のファイルよりも優先度が高い
  • 自作のスクリプトをサービス化する場合はこちらを使用
使い分けの原則: 自作のサービスやカスタマイズしたサービスは必ず/etc/systemd/system/に配置してください。この場所に配置することで、システムアップデート時に上書きされることを防ぎ、管理者が作成したサービスであることを明確にできます。

サービスユニットファイルの基本構造

ユニットファイルは、INI形式で記述され、主に3つのセクションから構成されます。

[Unit]
Description=サービスの説明
After=network.target

[Service]
Type=simple
ExecStart=/path/to/script
Restart=on-failure

[Install]
WantedBy=multi-user.target

[Unit]セクション

サービスの基本情報と依存関係を定義します。

  • Description: サービスの説明文
  • After: このサービスが起動する前に起動すべきサービス
  • Before: このサービスの後に起動すべきサービス
  • Requires: 必須の依存サービス
  • Wants: 推奨される依存サービス

[Service]セクション

サービスの実行方法を定義します。

  • Type: サービスのタイプ(simple, forking, oneshot など)
  • ExecStart: サービス起動時に実行するコマンド
  • ExecStop: サービス停止時に実行するコマンド
  • Restart: サービス異常終了時の再起動設定
  • User: サービスを実行するユーザー
  • Group: サービスを実行するグループ
root権限の使い分け: User=Group=を指定しない場合、サービスはroot権限で実行されます。セキュリティの観点から、root権限が不要な処理は専用のユーザーで実行することを推奨します。一方、システムの設定変更や特権ポートの使用など、root権限が必要な処理の場合は、これらの指定を省略してroot権限で実行します。

[Install]セクション

サービスの有効化に関する設定を定義します。

  • WantedBy: どのターゲットで有効にするか(通常はmulti-user.target
  • RequiredBy: 必須として有効にするターゲット

実践例1: シンプルなシェルスクリプトのサービス化

最も基本的な例として、簡単なシェルスクリプトをサービス化してみましょう。

ステップ1: スクリプトの作成

まず、サービス化するスクリプトを作成します。

sudo vi /usr/local/bin/hello-service.sh
#!/bin/bash
while true; do
    echo "$(date): Hello from systemd service" >> /var/log/hello-service.log
    sleep 60
done

実行権限を付与します。

sudo chmod +x /usr/local/bin/hello-service.sh

ステップ2: サービスユニットファイルの作成

sudo vi /etc/systemd/system/hello-service.service
[Unit]
Description=Hello Service Example
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/hello-service.sh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

ステップ3: サービスの有効化と起動

# systemdにユニットファイルを再読み込みさせる
sudo systemctl daemon-reload

# サービスを起動
sudo systemctl start hello-service

# サービスの状態確認
sudo systemctl status hello-service

# システム起動時の自動起動を有効化
sudo systemctl enable hello-service

実践例2: バックアップスクリプトの定期実行

バックアップスクリプトを定期的に実行する方法を2通り紹介します。

バックアップスクリプトの作成

sudo vi /usr/local/bin/backup.sh
#!/bin/bash
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
SOURCE_DIR="/home"

mkdir -p ${BACKUP_DIR}
tar -czf ${BACKUP_DIR}/home_backup_${DATE}.tar.gz ${SOURCE_DIR}

# 30日以上前のバックアップを削除
find ${BACKUP_DIR} -name "home_backup_*.tar.gz" -mtime +30 -delete

echo "$(date): Backup completed" >> /var/log/backup.log
sudo chmod +x /usr/local/bin/backup.sh

方法1: 通常のサービスとして実行

この方法では、スクリプト内でsleepを使って定期実行を実現します。

sudo vi /etc/systemd/system/backup.service
[Unit]
Description=Backup Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=root

[Install]
WantedBy=multi-user.target

ここではType=oneshotを使用しています。これは一度実行して終了するタイプのサービスに適しています。

方法2: systemdタイマーを使用

より柔軟で推奨される方法として、systemdタイマーを使用します。

サービスファイルの作成

sudo vi /etc/systemd/system/backup.service
[Unit]
Description=Backup Service
Wants=backup.timer

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=root

[Install]
WantedBy=multi-user.target

タイマーファイルの作成

sudo vi /etc/systemd/system/backup.timer
[Unit]
Description=Backup Timer
Requires=backup.service

[Timer]
OnCalendar=daily
OnCalendar=02:00
Persistent=true

[Install]
WantedBy=timers.target

タイマーの有効化と起動

sudo systemctl daemon-reload
sudo systemctl enable backup.timer
sudo systemctl start backup.timer

# タイマーの状態確認
sudo systemctl list-timers backup.timer

cronとsystemdタイマーの違い

systemdタイマーの利点:

  • systemdのログ管理機能(journalctl)と統合されている
  • サービスの依存関係を管理できる
  • サービスが実行されなかった場合の補完実行(Persistent=true)
  • より正確なスケジューリング
cronの特徴:

  • シンプルで習得が容易
  • 長年使われてきた実績
  • 多くの環境で標準的に使用されている

実務では、systemdが標準のシステムではsystemdタイマーを使用することが推奨されますが、互換性や既存システムとの統一性を考慮してcronを選択する場合もあります。

実践例3: 監視スクリプトのデーモン化

システムの状態を常時監視するスクリプトをデーモンとして動作させる例です。

監視スクリプトの作成

sudo vi /usr/local/bin/monitor.sh
#!/bin/bash
LOG_FILE="/var/log/monitor.log"
CHECK_INTERVAL=300  # 5分ごとにチェック

while true; do
    # ディスク使用率をチェック
    DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
    
    if [ ${DISK_USAGE} -gt 80 ]; then
        echo "$(date): WARNING - Disk usage is ${DISK_USAGE}%" >> ${LOG_FILE}
    fi
    
    # メモリ使用率をチェック
    MEM_USAGE=$(free | awk 'NR==2 {printf "%.0f", $3/$2*100}')
    
    if [ ${MEM_USAGE} -gt 90 ]; then
        echo "$(date): WARNING - Memory usage is ${MEM_USAGE}%" >> ${LOG_FILE}
    fi
    
    sleep ${CHECK_INTERVAL}
done
sudo chmod +x /usr/local/bin/monitor.sh

サービスファイルの作成

sudo vi /etc/systemd/system/monitor.service
[Unit]
Description=System Monitor Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/monitor.sh
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

この例では、Restart=alwaysを設定しているため、スクリプトが異常終了しても自動的に再起動されます。RestartSec=10により、再起動前に10秒間待機します。

sudo systemctl daemon-reload
sudo systemctl enable monitor.service
sudo systemctl start monitor.service

サービスの基本操作コマンド

systemdサービスを管理する基本的なコマンドを紹介します。

サービスの起動

sudo systemctl start サービス名.service

サービスを即座に起動します。.service拡張子は省略可能です。

サービスの停止

sudo systemctl stop サービス名.service

実行中のサービスを停止します。

サービスの再起動

sudo systemctl restart サービス名.service

サービスを一度停止してから再度起動します。設定ファイルを変更した場合などに使用します。

サービスの状態確認

sudo systemctl status サービス名.service

サービスの現在の状態、最近のログ、プロセスIDなどを表示します。

自動起動の有効化

sudo systemctl enable サービス名.service

システム起動時にサービスが自動的に起動するように設定します。

自動起動の無効化

sudo systemctl disable サービス名.service

システム起動時の自動起動を無効にします。

有効化と同時に起動

sudo systemctl enable --now サービス名.service

サービスを有効化すると同時に即座に起動します。

全サービスの一覧表示

systemctl list-units --type=service

現在読み込まれているすべてのサービスの状態を表示します。

ログの確認方法(journalctl)

systemdのサービスは、journalctlを使ってログを確認できます。

特定のサービスのログを表示

sudo journalctl -u サービス名.service

指定したサービスのログのみを表示します。

最新のログをリアルタイムで表示

sudo journalctl -u サービス名.service -f

tail -fのように、ログをリアルタイムで監視します。

指定した行数のログを表示

sudo journalctl -u サービス名.service -n 50

最新50行のログを表示します。

日時を指定してログを表示

sudo journalctl -u サービス名.service --since "2024-01-01" --until "2024-01-02"

指定した期間のログを表示します。

優先度を指定してログを表示

sudo journalctl -u サービス名.service -p err

エラーレベル以上のログのみを表示します。優先度はemergalertcriterrwarningnoticeinfodebugが指定できます。

トラブルシューティング

サービスが正常に動作しない場合の確認方法を紹介します。

ステップ1: 状態の確認

sudo systemctl status サービス名.service

まずはサービスの状態を確認します。Active: failedと表示されている場合は、サービスの起動に失敗しています。

ステップ2: ログの確認

sudo journalctl -u サービス名.service -n 100

直近のログを確認し、エラーメッセージを探します。

ステップ3: 設定ファイルの検証

sudo systemd-analyze verify /etc/systemd/system/サービス名.service

ユニットファイルの構文エラーをチェックします。

ステップ4: 実行権限の確認

ls -l /path/to/script

スクリプトに実行権限が付与されているか確認します。

ステップ5: スクリプトの単体テスト

sudo /path/to/script

スクリプトを直接実行して、エラーが発生しないか確認します。

よくあるエラーと対処法

「Permission denied」エラー

  • スクリプトに実行権限がない: chmod +xで権限を付与
  • User指定が不適切: root権限が必要な処理はUser=を削除
「No such file or directory」エラー

  • ExecStartのパスが間違っている: 絶対パスを使用
  • スクリプトのshebang行が間違っている: #!/bin/bashを確認
サービスが起動してもすぐに終了する

  • Type指定が不適切: 継続的に動作させる場合はType=simpleを使用
  • スクリプトが即座に終了している: ループ処理を追加

まとめ

今回は、RHEL系Linuxにおけるsystemdサービスの作成から管理方法まで、基礎から実践的な内容を解説しました。

重要なポイント:

  1. 自作サービスは/etc/systemd/system/に配置する
  2. ユニットファイルは[Unit]、[Service]、[Install]の3セクションで構成
  3. 定期実行にはsystemdタイマーの使用が推奨される
  4. 基本コマンド(start、stop、restart、status、enable、disable)を使いこなす
  5. ログ確認にはjournalctlを活用する
  6. root権限が不要な処理は専用ユーザーで実行する

systemdサービスを適切に作成・管理することで、システムの安定運用と自動化を実現できます。実務でスクリプトをサービス化する際は、この記事の内容を参考に、段階的に実装してみてください。

まずは簡単なスクリプトから始めて、徐々に複雑な処理をサービス化していくことで、systemdの理解が深まっていきます。ログの確認とトラブルシューティングの方法を身につけることで、問題が発生した際にも冷静に対処できるようになります。

 

【注意】

このブログは技術に関する知識や経験を共有することを目的としており、情報の正確性に努めていますが、その内容の正確性や完全性を保証するものではありません。ブログの情報を利用する場合は、自己の責任において行動してください。ブログの内容に基づいて行った行動や決定によって生じた損害や被害について、筆者は一切の責任を負いません。

 

記事の内容の一部は、生成AIで作成しています。

RHELITナレッジ
この記事の作者
StarTeller

30歳で異業種からITエンジニアへ転身し、10年以上にわたりインフラエンジニアとして様々な現場でシステム構築・運用に携わってきました。
得意分野はLinux/Windowsのサーバー構築・運用で、ネットワークやAWSなども実務で活用しています。このブログでは、これまでの業務で培った経験を基に、日々の業務で遭遇した問題の解決方法や、システム構築の具体的な手順を解説。現場のエンジニアが実際に「困ったとき」に参照できる情報を意識して投稿していこうと思っています。
※サーバ運用費がかかっているので、広告を掲載させて頂いてます。

StarTellerをフォローする
シェアする
StarTellerをフォローする

コメント

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