Linuxサーバーを運用する上で、Webサーバーやデータベースなどのサービス管理は避けて通れません。現在のほとんどのLinuxディストリビューションでは、systemdがサービス管理の中核を担っています。
この記事では、systemdの基本概念からsystemctlコマンドによるサービス制御、Unitファイルの読み方、journalctlによるログ確認、そして自作サービスの登録まで、systemdによるサービス管理を体系的に解説します。
前提条件と動作確認環境
本記事の内容は以下の環境で動作確認しています。
| 項目 | 内容 |
|---|---|
| OS | Ubuntu 24.04 LTS / AlmaLinux 9 |
| systemd | 255 |
| シェル | bash 5.2 |
基本的なLinuxコマンドライン操作ができることを前提としています。WSL2環境でもsystemdを有効化することで利用可能です。
systemdとは
systemdは、Linuxシステムの起動処理とサービス管理を担う初期化システム(initシステム)です。2010年にRed Hatのエンジニアによって開発が始まり、現在ではUbuntu、Debian、CentOS、Fedora、Arch Linuxなど、主要なディストリビューションの標準として採用されています。
従来のinit(SysVinit)との違い
systemd登場以前は、SysVinitが長年にわたってLinuxの初期化システムとして使われていました。両者の主な違いを見てみましょう。
| 項目 | SysVinit | systemd |
|---|---|---|
| 起動方式 | 順次起動(シーケンシャル) | 並列起動(パラレル) |
| 設定ファイル | シェルスクリプト | 宣言的なUnitファイル |
| 依存関係 | 番号順による暗黙的な制御 | 明示的な依存関係定義 |
| 起動速度 | 遅い | 高速 |
| プロセス監視 | 限定的 | cgroupsによる完全な追跡 |
| ログ管理 | syslog別管理 | journald統合 |
graph TB
subgraph SysVinit
A1[カーネル] --> A2[init]
A2 --> A3[S01script]
A3 --> A4[S02script]
A4 --> A5[S03script]
A5 --> A6[...]
end
subgraph systemd
B1[カーネル] --> B2[systemd]
B2 --> B3[service1]
B2 --> B4[service2]
B2 --> B5[service3]
B3 --> B6[依存サービス]
endsystemdの並列起動により、システムの起動時間が大幅に短縮されます。また、依存関係を明示的に定義できるため、サービス間の関係が明確になります。
systemdの主要コンポーネント
systemdは単なる初期化システムではなく、複数のコンポーネントから構成される包括的なシステム管理スイートです。
| コンポーネント | 役割 |
|---|---|
| systemd | PID 1として動作するメインプロセス |
| systemctl | サービス管理のためのコマンドラインツール |
| journald | ログ収集・管理デーモン |
| journalctl | journaldのログを閲覧するツール |
| logind | ログインセッション管理 |
| networkd | ネットワーク設定管理 |
| resolved | DNS解決 |
| timedatectl | 日時設定管理 |
Unit(ユニット)の概念
systemdでは、管理対象のリソースを「Unit(ユニット)」という単位で扱います。サービスだけでなく、マウントポイントやデバイス、タイマーなども含まれます。
Unitの種類
主要なUnitタイプを理解しておきましょう。
| Unitタイプ | 拡張子 | 説明 |
|---|---|---|
| Service | .service | デーモンやバックグラウンドプロセス |
| Socket | .socket | ソケットベースのアクティベーション |
| Target | .target | 複数Unitのグループ化(旧ランレベル相当) |
| Mount | .mount | ファイルシステムのマウントポイント |
| Timer | .timer | タイマーベースのスケジュール実行 |
| Device | .device | udevデバイス |
| Path | .path | ファイルシステムパスの監視 |
| Slice | .slice | リソース管理グループ |
日常的なサービス管理では、主に.serviceを扱います。定期実行には.timerが使われます。
Unitファイルの配置場所
Unitファイルは複数の場所に配置でき、優先順位が定められています。
| パス | 優先度 | 用途 |
|---|---|---|
| /etc/systemd/system/ | 最高 | 管理者が作成・カスタマイズするUnit |
| /run/systemd/system/ | 中 | ランタイムで生成される一時的なUnit |
| /usr/lib/systemd/system/ | 低 | パッケージがインストールするUnit |
カスタマイズする際は、/etc/systemd/system/にファイルを配置します。同名のUnitファイルが複数の場所にある場合、優先度の高いものが使用されます。
systemctlによるサービス管理
systemctlは、systemdを操作するためのメインコマンドです。サービスの起動・停止・状態確認など、日常的な管理作業のほとんどをsystemctlで行います。
サービスの状態確認(status)
サービスの現在の状態を確認するには、systemctl statusを使用します。
|
|
出力例:
|
|
statusコマンドの出力には、重要な情報が含まれています。
| フィールド | 説明 |
|---|---|
| Loaded | Unitファイルの読み込み状態と自動起動設定 |
| Active | サービスの実行状態(active/inactive/failed) |
| Main PID | メインプロセスのPID |
| Tasks | 起動しているタスク数 |
| Memory | メモリ使用量 |
| CGroup | コントロールグループのプロセスツリー |
先頭の「●」の色にも意味があります。緑は正常動作中、赤は失敗、白は非アクティブを示します。
サービスの起動と停止
サービスを起動するにはstart、停止するにはstopを使用します。
|
|
restartとreloadの使い分けは重要です。
| コマンド | 動作 | ダウンタイム |
|---|---|---|
| restart | プロセスを停止して再起動 | あり(短い) |
| reload | プロセス維持のまま設定再読み込み | なし |
設定変更後は、可能であればreloadを使用することで、サービスの継続性を保てます。ただし、すべてのサービスがreloadに対応しているわけではありません。
自動起動の設定(enable/disable)
システム起動時にサービスを自動的に開始させるには、enableを使用します。
|
|
enableコマンドは、指定したUnitファイルへのシンボリックリンクを/etc/systemd/system/配下に作成します。
|
|
enableとstartを同時に行うこともできます。
|
|
サービス一覧の表示
システム上のサービス一覧を確認するには、list-unitsまたはlist-unit-filesを使用します。
|
|
list-unit-filesの出力例:
|
|
STATEカラムの意味:
| 状態 | 説明 |
|---|---|
| enabled | 自動起動が有効 |
| disabled | 自動起動が無効 |
| static | 他のUnitからのみ起動される |
| masked | 完全に無効化されている |
サービスの完全無効化(mask)
disableはシンボリックリンクを削除するだけですが、maskを使うと他のUnitからの依存関係による起動も含めて完全に無効化できます。
|
|
maskは、Unitファイルを/dev/nullへのシンボリックリンクに置き換えることで実現されています。
Unitファイルの読み方と構造
systemdのサービスを深く理解するには、Unitファイルの構造を知る必要があります。ここでは、実際のUnitファイルを読み解いてみましょう。
基本的なUnitファイルの構造
Unitファイルはセクションに分かれており、それぞれにディレクティブ(設定項目)を記述します。
|
|
[Unit]セクション
[Unit]セクションには、サービスの説明と依存関係を記述します。
| ディレクティブ | 説明 |
|---|---|
| Description | サービスの説明文 |
| Documentation | ドキュメントへの参照 |
| After | このUnitより先に起動すべきUnit |
| Before | このUnitより後に起動すべきUnit |
| Requires | 必須の依存Unit(失敗時は自分も停止) |
| Wants | 推奨の依存Unit(失敗しても継続) |
| Conflicts | 同時に実行できないUnit |
After/Beforeは起動順序のみを制御し、Requires/Wantsは依存関係を定義します。両方を組み合わせて使用することが一般的です。
|
|
[Service]セクション
[Service]セクションには、サービスの実行方法を記述します。
主要なディレクティブ:
| ディレクティブ | 説明 |
|---|---|
| Type | サービスタイプ(後述) |
| ExecStart | 起動時に実行するコマンド |
| ExecStop | 停止時に実行するコマンド |
| ExecReload | reload時に実行するコマンド |
| Restart | プロセス終了時の再起動条件 |
| RestartSec | 再起動までの待機秒数 |
| User | 実行ユーザー |
| Group | 実行グループ |
| WorkingDirectory | 作業ディレクトリ |
| Environment | 環境変数 |
| EnvironmentFile | 環境変数ファイル |
Typeディレクティブの種類
Typeはサービスの起動方式を指定します。適切なTypeを選択することが重要です。
| Type | 説明 | 代表例 |
|---|---|---|
| simple | ExecStartがメインプロセス(デフォルト) | 一般的なデーモン |
| forking | fork後に親プロセスが終了 | nginx、Apache(従来型) |
| oneshot | 完了まで待機(1回実行) | 初期化スクリプト |
| notify | 起動完了をsystemdに通知 | PostgreSQL |
| dbus | D-Bus名の取得で起動完了と判断 | D-Bus対応サービス |
| idle | 他のジョブ完了後に実行 | 優先度の低いサービス |
graph LR
subgraph "Type=simple"
A1[systemctl start] --> A2[ExecStart実行]
A2 --> A3[即座に起動完了と判断]
end
subgraph "Type=forking"
B1[systemctl start] --> B2[ExecStart実行]
B2 --> B3[親プロセスfork]
B3 --> B4[親プロセス終了]
B4 --> B5[起動完了と判断]
end
subgraph "Type=notify"
C1[systemctl start] --> C2[ExecStart実行]
C2 --> C3[初期化処理]
C3 --> C4[sd_notify送信]
C4 --> C5[起動完了と判断]
endRestartディレクティブの設定
プロセスが異常終了した場合の自動再起動を設定できます。
| 値 | 説明 |
|---|---|
| no | 再起動しない(デフォルト) |
| on-success | 正常終了時のみ再起動 |
| on-failure | 異常終了時のみ再起動 |
| on-abnormal | シグナル・タイムアウト時に再起動 |
| on-abort | キャッチされないシグナル時に再起動 |
| always | 常に再起動 |
|
|
[Install]セクション
[Install]セクションは、systemctl enable実行時の動作を定義します。
| ディレクティブ | 説明 |
|---|---|
| WantedBy | enableでシンボリックリンクを作成するtarget |
| RequiredBy | enable時に必須としてリンクを作成するtarget |
| Also | enableで一緒にenableするUnit |
| Alias | Unitの別名 |
|
|
WantedBy=multi-user.targetは最も一般的な設定で、通常のLinux起動時にサービスを開始することを意味します。
実際のUnitファイル例
実運用されているnginxのUnitファイルを見てみましょう。
|
|
|
|
このUnitファイルから読み取れる内容:
After=network.target: ネットワーク起動後に開始Type=forking: 起動時にforkするタイプExecStartPre: 起動前に設定ファイルの構文チェックPIDFile: PIDファイルの場所を指定PrivateTmp=true: 専用の/tmpディレクトリを使用(セキュリティ強化)
journalctlによるログ確認
systemdには、ログ管理システムであるjournaldが統合されています。journalctlコマンドを使用して、システムおよびサービスのログを確認できます。
基本的なログ確認
|
|
サービスのログをフィルタリング
特定のサービスのログのみを表示するには、-uオプションを使用します。
|
|
時間でフィルタリング
特定の時間範囲のログを確認することもできます。
|
|
優先度でフィルタリング
ログの重要度(優先度)でフィルタリングできます。
|
|
優先度レベル:
| レベル | 意味 |
|---|---|
| emerg (0) | 緊急 |
| alert (1) | 警報 |
| crit (2) | 致命的 |
| err (3) | エラー |
| warning (4) | 警告 |
| notice (5) | 通知 |
| info (6) | 情報 |
| debug (7) | デバッグ |
出力形式の変更
|
|
ディスク使用量の確認と管理
journalのログはディスク容量を消費するため、定期的な管理が必要です。
|
|
自作サービスの登録
独自のアプリケーションをsystemdサービスとして登録する方法を解説します。
シンプルなサービスの作成
例として、Node.jsアプリケーションをサービス化してみましょう。
まず、Unitファイルを作成します。
|
|
|
|
サービスの有効化と起動
Unitファイルを作成または変更した後は、systemdにリロードを指示する必要があります。
|
|
環境変数ファイルの使用
機密情報を含む環境変数は、別ファイルに分離することをお勧めします。
|
|
|
|
Unitファイルでファイルを参照:
|
|
起動スクリプトを使用する例
より複雑な起動処理が必要な場合は、ラッパースクリプトを使用します。
|
|
|
|
|
|
Unitファイル:
|
|
セキュリティ強化オプション
本番環境では、セキュリティを強化するオプションを追加することをお勧めします。
|
|
実践的なトラブルシューティング
systemdでサービス管理を行う際によくある問題とその解決方法を紹介します。
サービスが起動しない場合
- 状態を確認する
|
|
- 詳細なログを確認する
|
|
- 設定ファイルの構文をチェックする
|
|
よくあるエラーと対処法
| エラー | 原因 | 対処法 |
|---|---|---|
| code=exited, status=203/EXEC | 実行ファイルが見つからない | ExecStartのパスを確認 |
| code=exited, status=217/USER | 指定ユーザーが存在しない | User/Groupの設定を確認 |
| code=exited, status=200/CHDIR | 作業ディレクトリが存在しない | WorkingDirectoryを確認 |
| code=exited, status=1/FAILURE | アプリケーションエラー | journalctlでログを確認 |
依存関係の確認
サービスの依存関係を確認するには:
|
|
起動時間の分析
システムの起動時間やサービスごとの起動時間を分析:
|
|
まとめ
systemdは現代のLinuxシステムにおけるサービス管理の標準です。この記事では以下の内容を解説しました。
- systemdの基本概念と従来のSysVinitとの違い
systemctlコマンドによるサービス制御(start/stop/restart/status/enable/disable)- Unitファイルの構造と各セクションの役割
journalctlによるログ確認とフィルタリング- 自作サービスの登録方法とセキュリティ設定
systemdを使いこなすことで、サービスの起動・停止、自動起動設定、ログ確認、トラブルシューティングを効率的に行えるようになります。まずは日常的に使用するサービスでsystemctl statusやjournalctlを試し、徐々にカスタムサービスの作成にも挑戦してみてください。