でも、これらは誰が起動して、異常終了したら誰が再起動して、OS再起動後も誰が面倒を見るのか?
この問いに答えるのが「サービス管理」の仕組みです。このセクションでは:
- 常駐プロセス(デーモン)とは何か
- デーモンを管理する仕組みの進化(SysVinit → systemd)
- systemdを使ったサービスの登録・起動・停止(演習)
を学びます。
デーモン(常駐プロセス)とは
主にバックグラウンドで動作するプロセス(標準入出力から切り離されている)のことです。常時起動させておくプロセスはデーモン化するのが通例です。
デーモンを前提にされている有名なプロセスには名前の末尾に d がついています:
- httpd(Webサーバー)
- sshd(SSH接続の待ち受け)
- crond(cron、前セクションで学んだもの)
- named(DNS)
init系システム ― デーモンを管理する仕組み
デーモンは直接コマンドで起動することもできます(例:/usr/sbin/httpd -k start)。しかしこの方法だと:
- OS再起動したらプロセスが消えてしまう(永続化できない)
- 異常終了しても誰も再起動してくれない
- サービスごとに起動コマンドが違い、管理がバラバラになる
サーバーは24時間動き続ける必要があるため、「OS起動時に自動で立ち上げ、統一的に管理する仕組み」 が必要です。それがinit系システムです。
OS起動時、カーネルが最初に起動するプロセス(PID 1)が init です。このinitが設定に従って各種デーモンを起動します。
OS起動の流れ:
1. ブートローダーがカーネルを起動
2. カーネルがinitプロセスを起動(PID 1)
3. initが設定に従い各種デーモンを起動 このinit系システムは時代とともに進化してきました。
SysVinit(従来の仕組み)
長年使われてきたinit系システムです。
仕組み: /etc/init.d/ にシェルスクリプトで起動・停止ロジックを記述し、/etc/init.d/hoge start で起動する。
init.dスクリプトの例(/etc/init.d/httpd のイメージ):
#!/bin/bash
case "$1" in
start)
/usr/sbin/httpd -k start
;;
stop)
/usr/sbin/httpd -k stop
;;
restart)
/usr/sbin/httpd -k stop
/usr/sbin/httpd -k start
;;
esac 操作コマンド:
/etc/init.d/httpd start
/etc/init.d/httpd stop
/etc/init.d/httpd status このように、起動・停止のロジックをすべてシェルスクリプトで自分で書く必要があります。
デメリット:
- 起動スクリプトの問題が検知しにくい(シェルスクリプトなので実行するまでエラーに気づけない。失敗してもログの出力先がバラバラで原因を追いにくい)
- サービスが逐次(1つずつ順番に)起動するため起動が遅い
- サービス間の依存関係の管理が難しい
逐次起動のイメージ:
SysVinitではランレベル(起動モード)ごとのディレクトリに、/etc/init.d/ のスクリプトへのシンボリックリンクを番号付きで配置し、番号順に実行します:
/etc/rc.d/rc3.d/
├── S01network # 1番目:ネットワーク起動
├── S02syslog # 2番目:ログ起動
├── S03sshd # 3番目:SSH起動
├── S04httpd # 4番目:Webサーバー起動
├── S05crond # 5番目:cron起動
└── ... 1つずつ順番に起動するため、数が増えるほどOS起動が遅くなります。また、例えばhttpdとcrondは本来同時に起動できるのに、順番待ちが発生します。
systemd(現在の標準)
SysVinitの逐次起動の問題を解決し、依存関係に基づいてサービスを並列起動するため、OS起動が高速に完了します。
systemdが提供する機能
- システム・サービス管理:
systemctlコマンド - ログ管理:
journalctlコマンド - システムユーザー・グループ管理
- ログインセッション管理
- デバイス管理
- その他多数
Unit(ユニット)とは
/etc/init.d/ スクリプトに相当するものです。 1ファイル=1サービスの定義という点は同じですが、シェルスクリプトではなく宣言的な設定ファイルで記述します。Unitは11種類に分類されます。
Unitファイルの配置場所:
-
/etc/systemd/system/… 管理者が作成するUnitファイル(後の演習で使う) -
/usr/lib/systemd/system/… パッケージがインストールするUnitファイル
代表的なUnit種別:
-
.service… サービス(デーモン)の管理 ← 演習で使うのはこれ -
.timer… 定期実行(cronの代替) -
.socket… ソケットの管理 -
.mount… マウントポイントの管理
Unitファイルが存在するサービスは systemctl コマンドで操作できます。例えば httpd パッケージをインストールすると httpd.service のUnitファイルが自動的に配置されるため、以下のように操作できるようになります:
systemctl start httpd # 起動
systemctl stop httpd # 停止
systemctl status httpd # 状態確認 演習では、自作スクリプト用のUnitファイルを自分で書いてサービス化します。
一覧は以下で確認できます:
systemctl list-units -a 用語の整理
ここまでで「デーモン」「サービス」「Unit」と似た言葉が出てきたので整理します:
つまり:デーモンをsystemdで管理すると「サービス(.service Unit)」になる、という関係です。
- デーモン:バックグラウンドで動くプロセスの一般的な呼び名
- サービス(.service):systemdにおけるUnit種別の1つ。デーモンをsystemdで管理するときの単位
- Unit:systemdが管理するリソースの総称(サービス以外にtimerやsocketなども含む)
systemdでサービス登録・起動・停止(演習)
systemdのサービス管理にはroot(システム管理者)権限が必要です。全コマンドに sudo をつける必要がありますが、本演習ではパーミッションエラーを避けるためrootユーザーで直接操作します。
※ 本来、rootでの常時作業はセキュリティの観点から推奨されません。演習のための措置です。
まずrootユーザーになります:
% sudo su - 確認:
# whoami
root
# pwd
/root 【登録】サービスとして登録する
まず、デーモンとして動かすスクリプトを作成し、Unitファイルを書いてsystemdに登録します。
1. サービス用スクリプトを作成する
/root/date_memory.sh を作成します:
# vim date_memory.sh スクリプトの内容:
#!/bin/bash
while true
do
var1=`date`
var2=`cat /proc/meminfo | grep "MemFree"`
echo ${var1} ${var2} >> /tmp/date_memory.txt
sleep 3
done chmodこのスクリプトの動作: 無限ループで3秒ごとに現在の日時とメモリの空き容量を /tmp/date_memory.txt に追記し続けます。これをsystemdでデーモンとして管理します。
実行権限を付与:
# chmod +x date_memory.sh 2. Unitファイルを作成する
/etc/systemd/system/date_memory.service を作成します:
# vim /etc/systemd/system/date_memory.service ファイルの内容:
[Unit]
Description=date_memory daemon
[Service]
ExecStart=/root/date_memory.sh
Restart=always
Type=simple
[Install]
WantedBy=multi-user.target 各セクションの役割:
-
[Unit]:サービスの説明 -
[Service]:実行するコマンドや再起動ポリシーの定義 -
[Install]:どのtargetに属するかの宣言。targetは複数のUnitをまとめて起動するための仕組みで、WantedBy=multi-user.targetは「OS起動時にmulti-user.targetのグループとしてまとめて起動してほしい」という意味。systemctl enableでこの紐づけが有効になる
3. 登録を確認する
# systemctl list-unit-files --type=service | grep date_memory Restart=always と enable の違い(重要): この2つは別の概念です。Restart=always だけではOS再起動後にサービスは起動しません。OS起動時に自動起動させるには enable が必要です。
multi-user.target に紐づけるとOS起動時に起動するのか: systemdはOS起動時に「デフォルトtarget」を目標として処理を開始し、そこに紐づくサービスをまとめて起動します。サーバー環境ではデフォルトtargetが multi-user.target に設定されているため、ここに紐づけたサービスはOS起動時に自動起動します。(systemctl get-default で確認できます)
【起動】サービスを起動する
1. 有効化と起動
# systemctl enable date_memory
# systemctl start date_memory -
enable:OS起動時に自動起動するよう登録 -
start:今すぐサービスを起動
2. ステータスを確認する
# systemctl status date_memory 3. 出力を確認する
サービスが動いているので、3秒ごとにデータが追記されているはずです:
# cat /tmp/date_memory.txt 4. 再起動後の自動起動を確認する
enable を設定したので、OS再起動後もサービスが自動起動するはずです:
# reboot rebootするとSSH接続が切断されます。再起動が完了したら、再度SSHでログインしてrootになります:
% sudo su - /tmp/date_memory.txt を確認します:
# cat /tmp/date_memory.txt /tmp ディレクトリについて: /tmp は一時ファイル用のディレクトリです。Amazon Linux 2023では systemd-tmpfiles-clean.timer によって管理されており、再起動時に内容がクリアされる場合があります。そのため、再起動後のファイルには再起動以降のデータのみが記録されているはずです。
【停止】サービスを停止する
# systemctl stop date_memory 停止を確認:
# systemctl status date_memory rootから一般ユーザーに戻ります:
# exit systemd-journald(ちょっと演習)
systemd-journaldはsystemdのログ管理プロセスです。journalctlは一般ユーザーでも実行できます(一部のログ閲覧にはsudoが必要です)。
カーネル、syslog、systemd Unitの標準出力・標準エラー出力など、さまざまなソースからログ情報を収集・管理します。journalctl コマンドでログを人間が読める形式で表示できます。
基本的なログの表示
% journalctl (大量のログが出力されます)
ログをフィルタして表示
date_memoryのログを確認する(grepで絞り込み):
% journalctl | grep date_memory リアルタイムでログを追跡する
まず、date_memoryサービスを再度起動します:
% sudo systemctl start date_memory -f オプションでリアルタイムにログを追跡できます:
% journalctl -f -u date_memory.service (Ctrl+C で終了)
※ journalctlには便利なオプションが多数あり、journaldにも様々な設定があります。業務で必要になったときに調べてみてください。
まとめ
systemdの内容はかなり簡略化しています。この講義だけで「init/systemd完全に理解した!」とは言わないようにしましょう(怒られるらしいです)。
- サーバーには常時起動すべきデーモンがあり、それを管理する仕組みがinit系システム
- 現在の標準はsystemdで、
systemctlコマンドでサービスの登録・起動・停止ができる - Unitファイルを書いて
/etc/systemd/system/に置けば、自作プログラムもサービスとして管理できる
本講義では触れませんでしたが、systemdには timer unit という機能があり、cronのような定期実行をsystemdで管理できます。前のセクションでcronの代替として紹介した仕組みです。興味があれば本資料をベースに調べてみてください。