こんにちは、かつコーチです。
ここまでps・top・kill・シグナルとプロセス管理の基本を見てきましたが、実際の本番サーバーでnginxやMySQLがどのように起動・停止・再起動されているか、意識したことはあるでしょうか。
その答えがsystemdです。
この記事はここまでのシリーズを読了済みの上級者向けに、systemdの仕組みとサービス管理の実践を解説します。
systemdの仕組み
systemdは、Linuxのブートプロセスとサービス管理を担うinitシステム(システムが起動して最初に立ち上がり、他のすべてのプロセスの親となるプロセス)です。
Ubuntuを含む主要なディストリビューションが、旧来のSysVinit(シェルスクリプトベースの逐次起動方式)に代わって採用しています。
SysVinitはサービスを1つずつ順番に起動するため、依存関係が複雑になるほど起動が遅くなる傾向がありました。
systemdは並列起動・依存関係の宣言的な定義・ソケットベースのオンデマンド起動などを備え、起動の高速化と管理の一貫性を両立させています。systemctlという単一のコマンド体系で、サービスの起動・停止・自動起動設定・ログ確認までを統一的に扱えるのも大きな特徴です。
unitという管理単位
systemdは、管理対象をunit(ユニット)という単位で扱います。
主なunitの種類は以下の通りです。
| 種類 | 拡張子 | 役割 |
|---|---|---|
| service | .service | デーモン(常駐プログラム)の起動・停止 |
| timer | .timer | cronに相当する定期実行 |
| socket | .socket | ソケット待受によるオンデマンド起動 |
| target | .target | 複数unitをまとめるグループ(旧ランレベルに相当) |
本記事では、最も利用頻度の高いserviceを中心に解説します。
サービス管理の実践:systemctlの使い方
サービスの状態確認・起動・停止・再起動
サービスの状態確認はstatusで行います。
$ systemctl status nginx
● nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-09-02 09:00:00 JST; 3h ago
Main PID: 1120 (nginx)
Active行がactive (running)かinactive (dead)かで、現在の稼働状況が一目で分かります。
起動・停止・再起動は以下の通りです。
$ sudo systemctl start nginx
$ sudo systemctl stop nginx
$ sudo systemctl restart nginx
$ sudo systemctl reload nginx
restartはプロセスを一度完全に止めてから起動し直すのに対し、reloadは設定ファイルの変更だけをプロセスを止めずに反映します。
nginxの設定変更程度であればreloadの方が接続を切らずに済むため、可能な限りreloadを優先するのが実務での定石です。
自動起動の設定:enable・disable
サーバー再起動時にサービスを自動起動させるかどうかは、start/stopとは別にenable/disableで制御します。
$ sudo systemctl enable nginx
$ sudo systemctl disable nginx
startは「今すぐ起動する」、enableは「次回以降のブート時にも自動起動する」という、時間軸が異なる設定である点を明確に区別してください。
本番投入時にstartだけ実行してenableを忘れると、サーバー再起動後にサービスが立ち上がらないという事故につながります。
$ sudo systemctl enable --now nginx
--nowを付けることで、自動起動の有効化と即時起動を1コマンドで済ませられます。
journalctlでログを確認する
systemd管理下のサービスのログは、journalctlで統一的に確認できます。
$ journalctl -u nginx.service -n 50 --no-pager
$ journalctl -u nginx.service -f
-uでunit名を指定し、-n 50で直近50行、-fでtail -fのようにリアルタイム追尾ができます。/var/log/配下の個別ログファイルを探し回る必要がなく、サービス単位でログを一元的に追える点がsystemdの実務上の利点です。
unitファイルのカスタマイズと落とし穴
独自サービスの定義
自作のアプリケーションをsystemdで管理したい場合、/etc/systemd/system/配下にunitファイルを作成します。
# /etc/systemd/system/app-worker.service
[Unit]
Description=Application Queue Worker
After=network.target
[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/app
ExecStart=/usr/bin/php artisan queue:work
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
[Unit]セクションのAfterは起動順序の依存関係、[Service]セクションのRestart=alwaysはプロセスが異常終了した際の自動再起動、[Install]セクションのWantedByはどのtargetから有効化されるかを定義します。
作成後は以下のコマンドで反映します。
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now app-worker
daemon-reloadを忘れて変更が反映されない
私が実際にキューワーカーのunitファイルを本番サーバーで修正したとき、ExecStartのパスを直したにもかかわらず、何度restartしても古い挙動のままで悩んだことがあります。
❌Before:unitファイルを編集したあと、そのままsystemctl restartだけを実行する
$ sudo vi /etc/systemd/system/app-worker.service
$ sudo systemctl restart app-worker
systemdはunitファイルの内容を起動時に読み込んでキャッシュしており、ファイルを直接編集しただけでは、そのキャッシュが自動的に更新されません。
そのためrestartしても、変更前の設定のままプロセスが再起動されていました。
✅After:unitファイルを編集したら、必ずdaemon-reloadを挟んでからrestartする
$ sudo vi /etc/systemd/system/app-worker.service
$ sudo systemctl daemon-reload
$ sudo systemctl restart app-worker
daemon-reloadは、systemdに対して「unitファイルの定義が変わったので再読み込みしてほしい」と伝えるコマンドです。
unitファイルを編集した直後は、daemon-reloadを挟む習慣を徹底することで、この種のつまずきを避けられます。
Restart=alwaysが障害を隠蔽してしまう
もう1つの実体験として、Restart=alwaysを設定していたことで、実はアプリが起動直後にクラッシュを繰り返していたのに気づくのが遅れたことがあります。
❌Before:Restart=alwaysだけを設定し、statusがactiveであることに安心してしまう
$ systemctl status app-worker
Active: active (running) since ...
Restart=alwaysはプロセスが落ちるたびに自動で再起動するため、statusが一見activeに見えても、実際には数秒おきにクラッシュと再起動を繰り返している状態だったことがありました。
✅After:RestartSecと再起動回数の記録を合わせて確認し、異常な再起動頻度を検知する
$ journalctl -u app-worker --since "10 minutes ago" | grep -c "Started"
journalctlで直近の起動回数をカウントすることで、異常な頻度で再起動が発生していないかを確認できます。
必要に応じてStartLimitIntervalSec・StartLimitBurstを設定し、一定期間内に再起動が規定回数を超えたらsystemd自体が諦めて起動を止める、という保護を組み込んでおくと、障害の見逃しを防げます。
[Unit]
StartLimitIntervalSec=60
StartLimitBurst=5
応用:SysVinitとの違い・実務での判断軸
systemd以前のSysVinit(/etc/init.d/配下のシェルスクリプト)は、今も一部の古いパッケージや互換レイヤーとして残っていることがあります。
両者の主な違いを整理すると、以下のようになります。
| 項目 | SysVinit | systemd |
|---|---|---|
| 起動方式 | 逐次起動(順番待ち) | 並列起動(依存関係ベース) |
| 設定形式 | シェルスクリプト | 宣言的なunitファイル(INI形式) |
| ログ管理 | サービスごとに個別ファイル | journalctlで一元管理 |
| 自動再起動 | 個別に実装が必要 | Restart=で標準サポート |
Ubuntu 26.04 LTSを含む現行の主要ディストリビューションでは、実務上systemdへの理解が前提になっていると考えて差し支えありません。service nginx restartのようなSysVinit互換コマンドも動作はしますが、これは内部的にsystemdへ処理を委譲しているだけであり、unitファイルの構造やdaemon-reloadの必要性を理解した上でsystemctlを直接使う方が、トラブル時の対応速度に差が出ます。
まとめ
この記事のポイント
- systemdはLinuxのinitシステムで、unitという単位でサービス・タイマー・ソケットなどを管理する
start/stopは今の状態、enable/disableは次回起動時の自動起動設定という、時間軸の異なる制御- ログは
journalctl -u unit名でサービスごとに一元確認できる - unitファイルを編集したら、必ず
daemon-reloadを挟んでからrestartする Restart=alwaysは便利だが、クラッシュの繰り返しを隠蔽しうるため、journalctlでの再起動頻度の確認やStartLimitBurstの設定と併用する
次に読むべき記事
systemdでサービスの安定運用ができるようになったら、次はそのログをより深く読み解く「ログファイルの見方(/var/log、journalctl)」に進んでみてください。
本記事で触れたjournalctlの活用範囲が、さらに広がります。
タグ: Linux, 上級者向け, プロセス管理