RHEL 基礎 #4 systemd 入門 — サービス、target、journalctl
#3 でパッケージのインストールができるようになりました。インストールしたものを 起動 / 停止 / 起動時に自動で上げる / ログを見る 作業はすべて systemd の上で起きます。RHEL 7 からの標準で、Ubuntu をはじめほぼすべてのモダン Linux が同じモデルを使います。
RHEL 基礎 シリーズでこの記事の位置:
- #1 RHEL とは — Fedora から RHEL まで、そして AlmaLinux と Rocky Linux
- #2 セットアップ — RHEL 9 インストール、Subscription Manager、初ログイン
- #3 dnf とパッケージ管理 — repo、modules、AppStream
- #4 systemd 入門 — サービス、target、journalctl ← この記事
- #5 ユーザー/グループ/権限 — UID/GID、sudo、ACL
- #6 ファイルシステムの基本 — XFS、mount、/etc/fstab
- #7 基本セキュリティ — firewalld、SSH ハードニング
systemd とは何か #
Linux のブートが終わると、ユーザー領域で最初に立ち上がるプロセスが PID 1 です。昔は init (System V init)、今はほぼ全ディストリビューションで systemd です。
$ ps -p 1
PID TTY TIME CMD
1 ? 00:00:01 systemd
$ ls -l /sbin/init
lrwxrwxrwx. 1 root root ... /sbin/init -> ../lib/systemd/systemdsystemd は単純な init ではなく システム全体を管理するマネージャ です。仕事を一行ずつ整理すると:
- ブート順序を依存関係グラフで組み、並列で立ち上げる
- サービス (デーモン) の起動 / 停止 / 再起動 / 自動復旧
- マウント / スワップ / タイマー / ソケットなどの他のリソースも同じモデルで管理
- すべての子プロセスのログを
journaldで一か所に集める
旧 init は /etc/init.d/<サービス> start のようなシェルスクリプトでサービスを立ち上げていました。直列で動いて遅く、デバッグも難しかったです。systemd は 宣言型 です。「このサービスはどんな形で立ち上がるべきか」をテキストファイル (unit) に書いておけば、残りは systemd が処理してくれます。
unit の種類 #
systemd が扱う基本単位が unit です。いくつかの種類があります。
| 拡張子 | 意味 | 例 |
|---|---|---|
.service | デーモン / コマンド (一番よく使う) | nginx.service、sshd.service |
.socket | ソケット起動 | cockpit.socket |
.target | 複数 unit の束 (グループ) | multi-user.target |
.timer | 時間ベースのトリガー (cron 代替) | dnf-makecache.timer |
.mount | ファイルシステムのマウント | home.mount |
.path | ファイル変化の監視 | cups.path |
.slice / .scope | リソースグループ (cgroup) | user-1000.slice |
この記事では一番よく出会う service と target を本格的に扱い、それ以外は流れだけ押さえます。
systemctl — systemd と対話するコマンド #
systemctl 一つでほぼすべての systemd 操作ができます。
状態を見る — status
#
$ systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-04-12 10:01:32 JST; 1h ago
Docs: man:sshd(8)
Main PID: 942 (sshd)
Tasks: 1 (limit: 4632)
Memory: 5.2M
CPU: 30ms
CGroup: /system.slice/sshd.service
└─942 "sshd: /usr/sbin/sshd -D ..."
Apr 12 10:01:32 rhel9-lab systemd[1]: Starting OpenSSH server daemon...
Apr 12 10:01:32 rhel9-lab sshd[942]: Server listening on 0.0.0.0 port 22.
Apr 12 10:01:32 rhel9-lab systemd[1]: Started OpenSSH server daemon.status 一回で見えるもの:
- Loaded — unit ファイルのパス、enabled (起動時に自動起動) かどうか
- Active — 現在の動作状態 (
active (running)、inactive (dead)、failed…) - Main PID — メインプロセスの PID
- CGroup — 子プロセスがどの cgroup に属しているか
- 直近 10 行ほどの ログ — 最近何が起きたか
問題診断の最初のコマンドはほぼ常に systemctl status <サービス> です。
起動 / 停止 / 再起動 #
$ sudo systemctl start nginx # 起動
$ sudo systemctl stop nginx # 停止
$ sudo systemctl restart nginx # 再起動
$ sudo systemctl reload nginx # 設定だけ再読込 (対応する場合)restart と reload は違います。
- restart — プロセスを殺して立ち上げ直し。短いダウンタイムあり
- reload — 同じプロセスが SIGHUP のような信号を受けて設定だけを再読込。ダウンタイムなし。すべてのサービスが対応するわけではない (代表的に nginx、sshd は対応)
運用で設定だけ変えたなら reload が安全で、メモリ状態もリセットしたいなら restart。
起動時の自動起動 — enable / disable
#
$ sudo systemctl enable nginx # 起動時に自動起動
$ sudo systemctl disable nginx # 自動起動をオフ
$ sudo systemctl enable --now nginx # 即座に起動 + 起動時に自動enable と start は別の動作だと覚えておいてください。
| コマンド | 今 | 起動後 |
|---|---|---|
start | ✅ 起動 | ❌ 上がらない |
enable | ❌ 起動しない | ✅ 自動起動 |
enable --now | ✅ 起動 | ✅ 自動起動 |
--now はよく使うオプションです。「いまインストールしたサービスを今も立ち上げて、次の起動でも上げる」がほぼ常に望む動作です。
一覧を見る #
$ systemctl list-units --type=service # 現在メモリにあるサービス
$ systemctl list-unit-files --type=service # ディスクにあるすべての service unit
$ systemctl list-units --state=failed # 失敗したサービスだけ問題追跡の最初の一歩で --state=failed をよく見ます。起動直後に赤い行があるか確認。
target — システムの「モード」 #
旧 init の runlevel (0~6) を systemd は target に置き換えました。複数の unit をまとめた一種の「モード」です。
| target | 旧 runlevel | 意味 |
|---|---|---|
poweroff.target | 0 | 電源オフ |
rescue.target | 1 | シングルユーザー応急モード |
multi-user.target | 3 | テキストマルチユーザー (サーバーのデフォルト) |
graphical.target | 5 | GUI まで立てたマルチユーザー |
reboot.target | 6 | 再起動 |
$ systemctl get-default
graphical.target
$ systemctl is-active graphical.target
activeデフォルト target を変える #
GUI が要らない学習用マシンは multi-user.target で起動するとメモリ・CPU がぐっと軽くなります。
$ sudo systemctl set-default multi-user.target
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.
$ sudo rebootGUI に戻したくなれば set-default graphical.target。再起動なしで即座にモード切り替え:
$ sudo systemctl isolate multi-user.target # 今すぐテキストモードに
$ sudo systemctl isolate graphical.target # GUI に戻す応急 / 復旧モード #
ブートが壊れたマシンを救うときに使うモードです。GRUB ブートメニューから入ります。
| target | 用途 |
|---|---|
rescue.target | シングルユーザーモード。ほぼすべてのサービスが立ち上がっていない状態 + root で進入 |
emergency.target | さらに小さいモード。ファイルシステムも read-only でマウント |
GRUB 画面で e で編集し、カーネル行の末尾に systemd.unit=rescue.target を付けて Ctrl+X で起動。詳しいブート復旧は 上級 #1 で扱います。
最初の .service ユニットを直接作ってみる
#
人がインストールしたサービスを扱うだけでは systemd の半分。自分で unit を一枚書いてみるとモデル全体が頭に入ります。
小さな練習スクリプト #
まず systemd が起動する小さなスクリプトを作ります。
#!/bin/bash
while true; do
echo "[$(date +%H:%M:%S)] Hello from systemd"
sleep 5
done$ sudo chmod +x /usr/local/bin/hello-loop.shunit ファイルを書く #
[Unit]
Description=Hello loop demo
After=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hello-loop.sh
Restart=on-failure
RestartSec=2
User=nobody
[Install]
WantedBy=multi-user.target三つのセクションがあります。
[Unit] — このユニット自体のメタデータ。
Description—systemctl statusで表示される一行説明After— このユニットが起動する前に立ち上がっていてほしい他のユニット。依存関係。(強制依存はRequires)
[Service] — どう起動するか。
Type=simple— 最も一般的な形。ExecStartで立ち上げたプロセスがメインプロセス (他の形:forking、oneshot、notify…)ExecStart— 立ち上げるコマンド。絶対パス でRestart=on-failure— 異常終了時に自動再起動 (always/no/on-successも)RestartSec— 再起動の間隔 (秒)User=nobody— どのユーザーで実行するか。セキュリティ上 root 以外 に落とすのが基本
[Install] — enable したときの動作。
WantedBy=multi-user.target— この target が活性化されたときに一緒に起動。これがないとenableは動作しません。
有効化 #
$ sudo systemctl daemon-reload # 新しい unit ファイルを systemd に読ませる
$ sudo systemctl enable --now hello-loop
Created symlink ...
$ systemctl status hello-loop
● hello-loop.service - Hello loop demo
Loaded: loaded (/etc/systemd/system/hello-loop.service; enabled; ...)
Active: active (running) since ...
Main PID: 12345 (hello-loop.sh)
...
CGroup: /system.slice/hello-loop.service
├─12345 /bin/bash /usr/local/bin/hello-loop.sh
└─12389 sleep 5落とし穴 —
daemon-reloadの忘れが一番よくあります。unit ファイルを新しく作ったり修正したら、必ずdaemon-reload— でないと systemd が以前の定義で動きます。
unit ファイルをどこに置くかも大事です。
| パス | 用途 |
|---|---|
/usr/lib/systemd/system/ | パッケージがインストールした unit (直接編集禁止) |
/etc/systemd/system/ | ユーザーが作る / 上書きする unit |
~/.config/systemd/user/ | ユーザー単位 (user systemd) |
同名のファイルが両方にあれば /etc/systemd/system/ が優先 されます。パッケージ unit の一部だけ変えたい場合は systemctl edit <サービス> — drop-in ディレクトリに override ファイルを作ってくれます。
$ sudo systemctl edit nginx
# エディタが開いて /etc/systemd/system/nginx.service.d/override.conf を編集
[Service]
Environment="NGINX_OPTS=-q"
LimitNOFILE=65536オリジナルを触らずに設定を上書きできます。パッケージ更新でオリジナルが新しくなっても override は残ります。
journalctl — すべてのログが集まるところ #
systemd には journald というログデーモンが一緒に入っています。すべての unit の stdout/stderr、カーネルメッセージ、syslog まで一か所に集まります。
$ journalctl # 全部 (Page Down でスクロール)
$ journalctl -e # 末尾 (一番最近) へ
$ journalctl -f # リアルタイム follow (tail -f のように)
$ journalctl -n 100 # 直近 100 行だけフィルタ #
$ journalctl -u nginx # nginx unit のログだけ
$ journalctl -u nginx -f # nginx をリアルタイムで
$ journalctl -b # 今回の起動のログだけ
$ journalctl -b -1 # 一つ前の起動
$ journalctl --list-boots # 保存されている起動の一覧
$ journalctl --since "2026-04-12 10:00" --until "2026-04-12 11:00"
$ journalctl --since "1 hour ago"
$ journalctl --since today
$ journalctl -p err # err 以上の優先度
$ journalctl -p warning..err # 範囲よく使う組み合わせ #
$ journalctl -u sshd -f # sshd だけリアルタイムで見る
$ journalctl -u nginx --since today -p err # 今日のエラーだけ
$ journalctl _PID=12345 # 特定 PID のログ
$ journalctl _COMM=sudo # sudo コマンド自体のログfilter の _PID、_COMM、_UID のようなキーは journald が自動で埋めるメタデータです。journalctl -F _COMM でどんな値があるか覗けます。
journald の保存 #
デフォルトは 揮発性 で、再起動すると以前のログが消えます。永続保存を有効にするには次のコマンドを実行します。
$ sudo mkdir -p /var/log/journal
$ sudo systemd-tmpfiles --create --prefix /var/log/journal
$ sudo systemctl restart systemd-journaldその後 journalctl --list-boots で複数の起動が表示されれば永続保存がオンになっています。ディスク使用量の制限は /etc/systemd/journald.conf の SystemMaxUse=1G のような値で。
/etc/init.d/ はどこへ行ったか
#
古い資料を見ると service nginx start や /etc/init.d/nginx start といった表現がよく出ます。RHEL 9 ではどちらも動きますが、内部で systemctl に変換されます。
$ sudo service nginx status # systemctl status nginx に変換される
$ sudo chkconfig nginx on # systemctl enable nginx に変換される新しく覚える方は最初から systemctl で行くべきです。旧コマンドは古い資料を読むときに知っておく程度。
よく使うコマンド一表 #
| コマンド | する仕事 |
|---|---|
systemctl status <unit> | 状態 + 直近ログ |
systemctl start/stop/restart/reload <unit> | lifecycle |
systemctl enable [--now] <unit> | 起動時自動 (+ 即座に起動) |
systemctl disable [--now] <unit> | 自動起動解除 (+ 即座に停止) |
systemctl is-active/is-enabled <unit> | 一語で答え |
systemctl list-units --state=failed | 失敗した unit だけ |
systemctl daemon-reload | unit ファイル修正後に再読込 |
systemctl get-default / set-default | デフォルト target の確認 / 変更 |
systemctl isolate <target> | 即座に target を切り替え |
systemctl edit <unit> | drop-in override 編集 |
journalctl -u <unit> [-f] | その unit のログ (+ リアルタイム) |
journalctl -b [-1] | 今回/前回起動のログ |
journalctl --since "..." --until "..." | 時間範囲 |
journalctl -p err | 優先度フィルタ |
よく出会う落とし穴 #
「ユニットが見えない」 #
新しい unit ファイルを作ったのに systemctl start が “Unit not found” なら、ほぼ常に daemon-reload 忘れ。unit ファイルをディスクに置くだけで systemd が自動認識するわけではありません。
「enable したのに起動後に上がらない」 #
unit ファイルに [Install] セクションがない場合。WantedBy=multi-user.target 一行があって初めて enable に意味があります。systemctl enable が “no installation config” 系のメッセージを出したらこの問題です。
「Active: failed」 #
何が悪いか一番速く確認するには journalctl -u <unit> -e。起動直後にどんなエラーで死んだかを一画面で見せてくれます。
よくある原因:
ExecStartのコマンドが 相対パス (絶対パスでなければならない)- 実行ファイルに実行権限がない (
chmod +x) User=で指定したユーザーがファイルにアクセスできない (権限)Type=が実際の動作と合っていない
「ログが多すぎる」 #
journalctl だけ叩くと起動以降のすべてが出ます。ほぼ常に -u <unit>、-b、--since のいずれかを付けて絞ります。
まとめ #
この記事で押さえた絵:
- systemd が RHEL の PID 1 — すべてのブート/サービスを握っているマネージャ
- unit は systemd が扱う単位。service、target、timer、mount など複数の種類
systemctl status / start / stop / restart / reload / enable / disableが日常コマンド。enable --nowが実際にもっともよく使うオプション- target は旧 runlevel の代替。
multi-user.target(テキスト) /graphical.target(GUI) /rescue.target(応急) - 自分で書いた
.serviceユニットは/etc/systemd/system/に置き、daemon-reload後にenable --now systemctl editでパッケージ unit を触らずに drop-in override- journalctl がすべてのログが集まるところ —
-u、-b、--since、-p、-fの組み合わせで絞って見る
次 — ユーザーと権限 #
systemd がサービスをどのユーザーで起動するかは unit の User= 一行で決まります。そのユーザーがシステムにどう存在し、どのファイルにアクセスできるかのモデルが次の記事のテーマです。
#5 ユーザー/グループ/権限 — UID/GID、sudo、ACL では /etc/passwd と /etc/shadow の形、useradd / usermod / groupadd のコマンド群、ファイル権限 rwx の意味と chmod の二つの表記、もっと細かい権限が必要なときに使う ACL (getfacl/setfacl)、そして sudo と /etc/sudoers.d/ までを一度に押さえます。