Linux Boot Process and Systemd

Linux ブートプロセスと systemd 徹底解説

はじめに

Linux システムの起動プロセスは、電源投入からユーザーがログイン可能な状態に至るまで、複数の段階を経て実行される精密なオーケストレーションである。システム管理者にとって、このブートプロセスを深く理解することは、障害対応・パフォーマンスチューニング・セキュリティ強化の基盤となる。

本記事では、ファームウェア(BIOS/UEFI)からブートローダー(GRUB2)、カーネルのロード、initramfs、そして現代の Linux における初期化システムである systemd に至るまで、Linux ブートプロセスの全容を体系的に解説する。各段階について、アーキテクチャの概念だけでなく、具体的な設定例やトラブルシューティング手法を交えて実践的な知識を提供する。

本記事の対象読者

  • Linux システム管理者(初級〜中級)
  • インフラエンジニア
  • SRE(Site Reliability Engineer)
  • Linux の起動プロセスを体系的に学びたいエンジニア

本記事で扱う範囲

内容
第1章ファームウェア(BIOS / UEFI)
第2章ブートローダー(GRUB2)
第3章カーネルのロードと初期化
第4章initramfs(初期RAMファイルシステム)
第5章systemd の基本アーキテクチャ
第6章systemd ターゲットとランレベル
第7章Unit ファイルの詳細
第8章systemctl コマンド体系
第9章systemd ジャーナル(journald)
第10章タイマーとスケジューリング
第11章ブートプロセスのトラブルシューティング
第12章高度な設定とベストプラクティス

第1章: ファームウェア — BIOS と UEFI

1.1 BIOS(Basic Input/Output System)

BIOS は、1980年代から使われてきた従来型のファームウェアインターフェースである。電源投入直後に最初に実行されるソフトウェアであり、ハードウェアの初期化とブートデバイスの選択を行う。

BIOS の起動シーケンス

電源投入 → POST(Power-On Self-Test) → ブートデバイス検索 → MBR 読み込み → ブートローダー起動
  1. POST(Power-On Self-Test): CPU、メモリ、周辺デバイスの基本的な動作確認
  2. ブートデバイス検索: CMOS に保存された起動順序に従い、ブート可能なデバイスを検索
  3. MBR 読み込み: 最初のブートデバイスの先頭セクタ(512バイト)を読み込み
  4. 制御の移譲: MBR 内のブートローダーコードに制御を渡す

MBR(Master Boot Record)の構造

+---------------------------------------------------+
| ブートストラップコード(446バイト)                    |
+---------------------------------------------------+
| パーティションテーブル(64バイト = 16バイト × 4)      |
+---------------------------------------------------+
| ブートシグネチャ 0x55AA(2バイト)                    |
+---------------------------------------------------+
合計: 512バイト

MBR の制約:

  • 最大4つのプライマリパーティション
  • ディスクサイズは最大 2TB まで
  • ブートストラップコードのサイズが 446 バイトに制限

MBR の確認コマンド

# MBR の内容をダンプ
sudo dd if=/dev/sda bs=512 count=1 | hexdump -C

# パーティションテーブルの確認
sudo fdisk -l /dev/sda

# MBR のバックアップ
sudo dd if=/dev/sda of=/backup/mbr_backup.bin bs=512 count=1

# MBR の復元
sudo dd if=/backup/mbr_backup.bin of=/dev/sda bs=512 count=1

1.2 UEFI(Unified Extensible Firmware Interface)

UEFI は BIOS の後継として設計された現代的なファームウェアインターフェースである。2005年に UEFI Forum により策定され、現在ではほぼ全ての新しいシステムで採用されている。

UEFI の起動シーケンス

電源投入 → SEC → PEI → DXE → BDS → TSL → OS起動

各フェーズの詳細:

フェーズ名称説明
SECSecurity PhaseCPUの初期化、一時メモリ(CAR)の設定
PEIPre-EFI Initializationメモリの初期化、PEIMの実行
DXEDriver Execution Environmentデバイスドライバのロード、プロトコル登録
BDSBoot Device Selectionブートデバイスの選択、ブートマネージャの実行
TSLTransient System Loadブートローダー(GRUB等)の実行
RTRuntimeOS実行中のUEFIランタイムサービス

ESP(EFI System Partition)

UEFI ブートでは、ESP と呼ばれる特別なパーティションが必要である。

# ESP の確認
sudo fdisk -l | grep "EFI System"
# 出力例: /dev/sda1  2048  1050623  1048576  512M  EFI System

# ESP のマウント確認
mount | grep efi
# 出力例: /dev/sda1 on /boot/efi type vfat (rw,relatime,fmask=0077,dmask=0077,...)

# ESP 内の構造を確認
ls -la /boot/efi/EFI/
# 出力例:
# drwx------  4 root root 4096 Jan 15 10:00 .
# drwx------  3 root root 4096 Jan 15 10:00 ..
# drwx------  2 root root 4096 Jan 15 10:00 BOOT
# drwx------  2 root root 4096 Mar 20 14:30 ubuntu
# drwx------  2 root root 4096 Feb 10 09:00 centos

UEFI ブートエントリの管理

# 現在のブートエントリを一覧表示
sudo efibootmgr -v
# 出力例:
# BootCurrent: 0001
# Timeout: 5 seconds
# BootOrder: 0001,0002,0000
# Boot0000* EFI DVD/CDROM
# Boot0001* ubuntu        HD(1,GPT,abc123-...)/File(\EFI\ubuntu\shimx64.efi)
# Boot0002* CentOS Stream HD(1,GPT,def456-...)/File(\EFI\centos\shimx64.efi)

# 新しいブートエントリの追加
sudo efibootmgr --create \
  --disk /dev/sda \
  --part 1 \
  --loader /EFI/custom/bootx64.efi \
  --label "Custom Boot" \
  --verbose

# ブート順序の変更
sudo efibootmgr --bootorder 0002,0001,0000

# ブートエントリの削除
sudo efibootmgr --delete-bootnum --bootnum 0003

# 次回のみ特定のエントリからブート
sudo efibootmgr --bootnext 0002

Secure Boot

UEFI Secure Boot は、署名されたブートローダーとカーネルのみの実行を許可するセキュリティ機能である。

# Secure Boot の状態確認
mokutil --sb-state
# 出力例: SecureBoot enabled

# 登録済みの鍵を確認
mokutil --list-enrolled

# カスタムカーネルモジュールの署名
sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file \
  sha256 \
  /path/to/private_key.priv \
  /path/to/public_key.der \
  /path/to/module.ko

# MOK(Machine Owner Key)の登録
sudo mokutil --import /path/to/public_key.der
# 再起動後にMOKManagerで確認・登録

1.3 BIOS と UEFI の比較

特性BIOSUEFI
パーティションテーブルMBRGPT
最大ディスクサイズ2TB9.4ZB(理論値)
最大パーティション数4(プライマリ)128(GPT標準)
ブートコードサイズ446バイト実質無制限
ネットワークブートPXEHTTP Boot / PXE
セキュアブートなしあり
GUIなしあり(オプション)
ドライバモデル16ビット32/64ビット
起動速度遅い高速

第2章: ブートローダー — GRUB2

2.1 GRUB2 の概要

GRUB2(GRand Unified Bootloader version 2)は、GNU プロジェクトが開発するブートローダーであり、現在の主要な Linux ディストリビューションでデフォルトのブートローダーとして採用されている。

GRUB2 の主な特徴

  • 複数の OS のブートをサポート(マルチブート)
  • 多数のファイルシステムに対応(ext4, XFS, Btrfs, ZFS 等)
  • ネットワークブート対応
  • スクリプト言語によるカスタマイズ
  • モジュラー設計によるカスタマイズ性

2.2 GRUB2 のステージ

GRUB2 は、MBR の容量制限を克服するため、複数のステージに分かれて動作する。

BIOS 環境の場合

Stage 1 (boot.img)  →  Stage 1.5 (core.img)  →  Stage 2 (/boot/grub/)
   MBR内 446バイト       MBR後のギャップ領域        /boot パーティション
  • Stage 1(boot.img): MBR に格納される最小のコード。Stage 1.5 をロードする
  • Stage 1.5(core.img): MBR とパーティション間のギャップ(通常 31KB〜1MB)に格納。ファイルシステムドライバを含み、Stage 2 をロード可能にする
  • Stage 2: /boot/grub/ ディレクトリに格納されるモジュール群。メニュー表示、カーネルロード等の全機能を提供

UEFI 環境の場合

UEFI ファームウェア → ESP上の grubx64.efi → /boot/grub/ の設定・モジュール

2.3 GRUB2 の設定ファイル

メイン設定ファイル: /boot/grub/grub.cfg

このファイルは自動生成されるため、直接編集してはならない。

# grub.cfg の場所を確認
ls -la /boot/grub/grub.cfg
# UEFI の場合
ls -la /boot/efi/EFI/ubuntu/grub.cfg

# grub.cfg の再生成
sudo grub-mkconfig -o /boot/grub/grub.cfg
# RHEL/CentOS の場合
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

カスタマイズファイル: /etc/default/grub

# /etc/default/grub の設定例
cat /etc/default/grub
# デフォルトのブートエントリ(0始まり、またはメニューエントリ名)
GRUB_DEFAULT=0

# 前回起動したエントリを記憶
# GRUB_DEFAULT=saved
# GRUB_SAVEDEFAULT=true

# タイムアウト(秒)
GRUB_TIMEOUT=5

# タイムアウトのスタイル(menu: 常に表示, countdown: カウントダウン, hidden: 非表示)
GRUB_TIMEOUT_STYLE=menu

# ブートメニューの表示名
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release 2>/dev/null || echo 'Linux')"

# カーネルパラメータ(全エントリに適用)
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"

# カーネルパラメータ(通常エントリのみに適用、リカバリーには適用されない)
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

# コンソール設定(シリアルコンソール出力)
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"

# 解像度の設定
GRUB_GFXMODE=1024x768

# OS プローブの無効化(マルチブートが不要な場合)
GRUB_DISABLE_OS_PROBER=true

# リカバリーエントリの無効化
# GRUB_DISABLE_RECOVERY=true

カスタムメニューエントリ: /etc/grub.d/

# /etc/grub.d/ ディレクトリの内容
ls -la /etc/grub.d/
# 出力例:
# -rwxr-xr-x 1 root root 10627 00_header
# -rwxr-xr-x 1 root root 12960 10_linux
# -rwxr-xr-x 1 root root 12674 20_linux_xen
# -rwxr-xr-x 1 root root 12264 30_os-prober
# -rwxr-xr-x 1 root root   214 40_custom
# -rwxr-xr-x 1 root root   216 41_custom

各ファイルの役割:

ファイル説明
00_headerGRUB の基本設定(タイムアウト、デフォルトエントリ等)
10_linuxインストール済み Linux カーネルのエントリ自動生成
20_linux_xenXen ハイパーバイザー用のエントリ
30_os-prober他の OS の検出とエントリ追加
40_customユーザーカスタムエントリ
41_custom追加のカスタムエントリ

40_custom にカスタムエントリを追加する例

sudo cat >> /etc/grub.d/40_custom << 'EOF'

# メモリテスト用エントリ
menuentry "Memtest86+" {
    linux /boot/memtest86+.bin
}

# レスキュー用 ISO からのブート
menuentry "SystemRescue ISO" {
    set isofile="/boot/systemrescue.iso"
    loopback loop $isofile
    linux (loop)/sysresccd/boot/x86_64/vmlinuz archisobasedir=sysresccd img_dev=/dev/sda2 img_loop=$isofile
    initrd (loop)/sysresccd/boot/x86_64/sysresccd.img
}

# チェインロードによる Windows の起動
menuentry "Windows 10" {
    insmod chain
    insmod ntfs
    set root=(hd0,gpt2)
    chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
EOF

2.4 GRUB2 のインストールと修復

# BIOS 環境での GRUB2 インストール
sudo grub-install /dev/sda
# または明示的にターゲットを指定
sudo grub-install --target=i386-pc /dev/sda

# UEFI 環境での GRUB2 インストール
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu

# インストール確認
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck

# GRUB の設定を再生成
sudo update-grub  # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg  # RHEL/CentOS

レスキューモードでの GRUB 修復

# ライブ USB から起動した場合の GRUB 修復手順

# 1. ルートパーティションのマウント
sudo mount /dev/sda2 /mnt

# 2. 必要なファイルシステムのバインドマウント
sudo mount --bind /dev  /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys  /mnt/sys

# 3. EFI パーティションのマウント(UEFI の場合)
sudo mount /dev/sda1 /mnt/boot/efi

# 4. chroot 環境に入る
sudo chroot /mnt

# 5. GRUB の再インストール
grub-install /dev/sda  # BIOS
grub-install --target=x86_64-efi --efi-directory=/boot/efi  # UEFI

# 6. 設定の再生成
update-grub

# 7. chroot を抜けてアンマウント
exit
sudo umount /mnt/boot/efi
sudo umount /mnt/dev
sudo umount /mnt/proc
sudo umount /mnt/sys
sudo umount /mnt

2.5 GRUB2 のコマンドラインインターフェース

GRUB メニューで c キーを押すと、GRUB コマンドラインに入ることができる。

# 使用可能なデバイスの一覧
grub> ls
# 出力例: (hd0) (hd0,gpt3) (hd0,gpt2) (hd0,gpt1)

# パーティションの内容を確認
grub> ls (hd0,gpt2)/
# 出力例: boot/ dev/ etc/ home/ ...

# ファイルの内容を表示
grub> cat (hd0,gpt2)/etc/os-release

# 手動でカーネルをロードして起動
grub> set root=(hd0,gpt2)
grub> linux /boot/vmlinuz-5.15.0 root=/dev/sda2 ro
grub> initrd /boot/initrd.img-5.15.0
grub> boot

# 環境変数の確認
grub> set
# 出力例: color_highlight=black/light-gray
#          color_normal=light-gray/black
#          default=0
#          ...

2.6 GRUB2 のパスワード保護

# パスワードハッシュの生成
grub-mkpasswd-pbkdf2
# Enter password: ********
# Reenter password: ********
# PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.XXXX...

# /etc/grub.d/40_custom にパスワード設定を追加
sudo cat >> /etc/grub.d/40_custom << 'EOF'

# スーパーユーザーの設定
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.XXXX...

# 通常ユーザーの追加(メニュー選択のみ可能)
password user1 plaintext_password
EOF

# 特定のメニューエントリを制限する場合
# 10_linux を編集して --unrestricted オプションを追加
# menuentry 'Ubuntu' --class ubuntu --unrestricted {
#     ...
# }

# 設定の再生成
sudo update-grub

第3章: カーネルのロードと初期化

3.1 カーネルのロードプロセス

GRUB2 がカーネルイメージ(vmlinuz)と初期 RAM ディスク(initrd/initramfs)をメモリにロードすると、制御がカーネルに移譲される。

カーネルロードの流れ

GRUB2 → vmlinuz をメモリにロード → 自己解凍 → カーネル初期化開始
          initramfs をメモリにロード

vmlinuz の構造

+-----------------------------+
| ブートセクタ / セットアップ    |  リアルモードコード
+-----------------------------+
| 圧縮されたカーネルイメージ     |  プロテクトモードコード
| (bzImage)                   |
+-----------------------------+
# カーネルイメージの確認
ls -la /boot/vmlinuz-*
# 出力例:
# -rw------- 1 root root 11539616 Mar 15 10:00 /boot/vmlinuz-5.15.0-91-generic
# -rw------- 1 root root 11542688 Feb 20 09:00 /boot/vmlinuz-5.15.0-89-generic

# カーネルイメージの情報を確認
file /boot/vmlinuz-$(uname -r)
# 出力例: /boot/vmlinuz-5.15.0-91-generic: Linux kernel x86 boot executable bzImage,
#          version 5.15.0-91-generic, RO-rootFS, swap_dev 0XB, Normal VGA

# 現在のカーネルバージョン
uname -r
# 出力例: 5.15.0-91-generic

# カーネルの詳細情報
uname -a
# 出力例: Linux server01 5.15.0-91-generic #101-Ubuntu SMP Tue Nov 14 13:30:08 UTC 2023
#          x86_64 x86_64 x86_64 GNU/Linux

3.2 カーネル初期化の詳細

カーネルの初期化は、大きく分けて以下のフェーズで進行する。

フェーズ1: アーキテクチャ固有の初期化

1. CPU の初期化とモード切り替え(リアルモード → プロテクトモード → ロングモード)
2. ページテーブルの設定
3. GDT/IDT の設定
4. CPU 機能の検出(SSE, AVX, AES-NI 等)

フェーズ2: カーネルサブシステムの初期化

1. メモリ管理サブシステム(ページアロケータ、スラブアロケータ)
2. スケジューラの初期化
3. 割り込みハンドラの設定
4. タイマーサブシステムの初期化
5. VFS(Virtual File System)の初期化
6. ネットワークスタックの初期化

フェーズ3: デバイスの初期化

1. PCI バスの列挙
2. ビルトインドライバの初期化
3. ACPI サブシステムの初期化
4. 各種デバイスドライバの初期化

3.3 カーネルパラメータ(カーネルコマンドライン)

カーネルパラメータは、ブート時にカーネルの動作を制御する重要な設定である。

# 現在のカーネルパラメータを確認
cat /proc/cmdline
# 出力例: BOOT_IMAGE=/boot/vmlinuz-5.15.0-91-generic root=UUID=abc123-... ro quiet splash

# 利用可能なカーネルパラメータの一覧(カーネルドキュメント参照)
# ドキュメントの場所
ls /usr/share/doc/linux-doc-*/Documentation/admin-guide/kernel-parameters.txt 2>/dev/null

主要なカーネルパラメータ

# === ルートファイルシステム関連 ===
root=/dev/sda2                    # ルートデバイスの指定
root=UUID=abc123-def456-...       # UUID による指定(推奨)
root=LABEL=rootfs                 # ラベルによる指定
rootfstype=ext4                   # ルートファイルシステムの種類
ro                                # ルートファイルシステムを読み取り専用でマウント
rw                                # ルートファイルシステムを読み書き可能でマウント

# === コンソール関連 ===
console=tty0                      # 仮想コンソール
console=ttyS0,115200n8            # シリアルコンソール(ボーレート115200, 8ビット, パリティなし)
quiet                             # 起動メッセージを最小限に
loglevel=3                        # カーネルログレベル(0-7, 値が小さいほど重要)

# === メモリ関連 ===
mem=4G                            # 使用メモリの制限
hugepagesz=2M hugepages=1024      # ヒュージページの設定
transparent_hugepage=never        # THP(Transparent Huge Pages)の無効化
swapaccount=1                     # swap のアカウンティングを有効化

# === CPU 関連 ===
maxcpus=4                         # 使用する CPU 数の制限
nosmt                             # SMT(Hyper-Threading)の無効化
isolcpus=2,3                      # 特定の CPU をスケジューラから隔離
nohz_full=2,3                     # 特定の CPU のタイマー割り込みを削減

# === セキュリティ関連 ===
selinux=1                         # SELinux の有効化
enforcing=0                       # SELinux を Permissive モードで起動
apparmor=1 security=apparmor      # AppArmor の有効化
audit=1                           # 監査サブシステムの有効化

# === トラブルシューティング関連 ===
single                            # シングルユーザーモードで起動
init=/bin/bash                    # init の代わりに bash を起動
systemd.unit=rescue.target        # レスキューターゲットで起動
systemd.unit=emergency.target     # 緊急ターゲットで起動
rd.break                          # initramfs シェルに入る(switch_root 前)
crashkernel=auto                  # kdump 用にメモリを予約
nomodeset                         # カーネルモードセッティングの無効化(GPU問題の切り分け)

# === ネットワーク関連 ===
ip=dhcp                           # ネットワークブート時の DHCP 設定
ip=192.168.1.100::192.168.1.1:255.255.255.0:hostname:eth0:none
                                  # 静的 IP 設定

# === ストレージ関連 ===
rd.lvm.lv=centos/root             # LVM 論理ボリュームの有効化
rd.luks.uuid=xxx                  # LUKS 暗号化ボリュームの指定
rd.md.uuid=xxx                    # MD RAID アレイの指定

3.4 カーネルパラメータの設定方法

恒久的な設定(/etc/default/grub)

# /etc/default/grub を編集
sudo vi /etc/default/grub

# 例: THP を無効にし、シリアルコンソールを追加
GRUB_CMDLINE_LINUX="crashkernel=auto transparent_hugepage=never console=tty0 console=ttyS0,115200n8"

# 設定を反映
sudo update-grub  # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg  # RHEL/CentOS

一時的な設定(GRUB メニューから)

1. GRUB メニューで 'e' キーを押す
2. 'linux' 行の末尾にパラメータを追加
3. Ctrl+X または F10 で起動

sysctl による実行時変更(一部のパラメータ)

# 実行時のカーネルパラメータを確認
sysctl -a | head -20

# パラメータの変更
sudo sysctl -w vm.swappiness=10
sudo sysctl -w net.ipv4.ip_forward=1

# 恒久的な設定
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.d/99-custom.conf
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.d/99-custom.conf
sudo sysctl --system  # 設定の再読み込み

3.5 カーネルモジュール

Linux カーネルはモジュラー設計を採用しており、必要に応じてモジュールを動的にロード・アンロードできる。

# ロードされているモジュールの一覧
lsmod
# 出力例:
# Module                  Size  Used by
# nf_tables             249856  0
# bridge                307200  0
# stp                    16384  1 bridge
# overlay               151552  0

# モジュール情報の表示
modinfo ext4
# 出力例:
# filename:       /lib/modules/5.15.0-91-generic/kernel/fs/ext4/ext4.ko
# softdep:        pre: crc32c
# license:        GPL
# description:    Fourth Extended Filesystem
# ...

# モジュールの手動ロード
sudo modprobe overlay

# モジュールのアンロード
sudo modprobe -r overlay

# モジュールのブラックリスト(ロードを禁止)
echo "blacklist nouveau" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
echo "options nouveau modeset=0" | sudo tee -a /etc/modprobe.d/blacklist-nouveau.conf

# モジュールの依存関係を再構築
sudo depmod -a

# カーネルモジュールの自動ロード設定
echo "br_netfilter" | sudo tee /etc/modules-load.d/br_netfilter.conf
# 起動時に br_netfilter モジュールが自動的にロードされる

第4章: initramfs(初期 RAM ファイルシステム)

4.1 initramfs の概要

initramfs(Initial RAM File System)は、カーネルが本来のルートファイルシステムをマウントする前に使用する一時的なファイルシステムである。カーネルが起動した直後、まだディスク上のルートファイルシステムにアクセスできない段階で必要なドライバやツールを提供する。

initramfs が必要な理由

  1. ストレージドライバ: ルートファイルシステムが存在するディスクにアクセスするためのドライバ(SCSI, NVMe, RAID 等)
  2. ファイルシステムドライバ: ルートファイルシステムのフォーマット(ext4, XFS, Btrfs 等)を読むためのドライバ
  3. LVM/RAID/暗号化: ルートファイルシステムが LVM、ソフトウェア RAID、LUKS 暗号化上にある場合のアセンブルツール
  4. ネットワークブート: NFS や iSCSI 経由でルートファイルシステムにアクセスする場合のネットワークドライバ

initrd vs initramfs

特性initrd(旧方式)initramfs(現行方式)
フォーマットブロックデバイスイメージcpio アーカイブ
マウント方式ループバックデバイスtmpfs に展開
メモリ効率固定サイズのため非効率必要な分だけ使用
キャッシュ二重キャッシュの問題なし
実装仮想ブロックデバイスファイルシステム直接展開

4.2 initramfs の内容確認

# initramfs ファイルの確認
ls -lh /boot/initrd.img-*
# 出力例:
# -rw-r--r-- 1 root root  60M Mar 15 10:00 /boot/initrd.img-5.15.0-91-generic
# -rw-r--r-- 1 root root  59M Feb 20 09:00 /boot/initrd.img-5.15.0-89-generic

# initramfs の内容を一覧表示
lsinitramfs /boot/initrd.img-$(uname -r) | head -30
# 出力例:
# .
# bin
# conf
# conf/conf.d
# etc
# etc/modprobe.d
# init
# lib
# lib/modules
# lib/modules/5.15.0-91-generic
# ...

# initramfs の内容を詳細に一覧表示
lsinitramfs -l /boot/initrd.img-$(uname -r) | head -20

# initramfs を展開して中身を確認
mkdir /tmp/initramfs_inspect
cd /tmp/initramfs_inspect

# 圧縮形式の確認
file /boot/initrd.img-$(uname -r)
# 出力例: /boot/initrd.img-...: gzip compressed data, ...

# 展開(gzip 圧縮の場合)
zcat /boot/initrd.img-$(uname -r) | cpio -idmv 2>/dev/null

# 展開(複数セグメントがある場合 - Debian/Ubuntu)
unmkinitramfs /boot/initrd.img-$(uname -r) /tmp/initramfs_inspect

# 展開後の構造を確認
find /tmp/initramfs_inspect -maxdepth 3 -type f | head -30

initramfs 内の重要なファイル

# init スクリプト(initramfs のエントリポイント)
cat /tmp/initramfs_inspect/init
# または
cat /tmp/initramfs_inspect/main/init

# 含まれるカーネルモジュール
find /tmp/initramfs_inspect -name "*.ko*" | head -20

# 含まれるバイナリ
ls /tmp/initramfs_inspect/bin/ 2>/dev/null
ls /tmp/initramfs_inspect/main/usr/bin/ 2>/dev/null

4.3 initramfs の生成と更新

Debian/Ubuntu の場合

# initramfs の再生成(現在のカーネル)
sudo update-initramfs -u

# 特定のカーネルバージョン用の initramfs を生成
sudo update-initramfs -c -k 5.15.0-91-generic

# 全てのカーネルバージョン用の initramfs を更新
sudo update-initramfs -u -k all

# initramfs 生成設定
cat /etc/initramfs-tools/initramfs.conf
# /etc/initramfs-tools/initramfs.conf の主要設定

# MODULES: initramfs に含めるモジュールの選択方針
# most    - ほとんどのモジュールを含める(デフォルト、互換性重視)
# dep     - 現在のハードウェアに必要なモジュールのみ(サイズ縮小)
# netboot - ネットワークブートに必要なモジュール
# list    - /etc/initramfs-tools/modules にリストされたもののみ
MODULES=most

# BUSYBOX: BusyBox を含めるか
BUSYBOX=auto

# COMPRESS: 圧縮方式
# gzip, bzip2, lz4, lzma, lzop, xz, zstd
COMPRESS=zstd

# NFSROOT: NFS ルートファイルシステムの設定(ネットワークブート用)
# NFSROOT=auto
# 追加のモジュールを指定
echo "vfio-pci" | sudo tee -a /etc/initramfs-tools/modules

# カスタムスクリプトの追加
# /etc/initramfs-tools/hooks/ - initramfs ビルド時に実行
# /etc/initramfs-tools/scripts/ - ブート時に実行

RHEL/CentOS の場合(dracut)

# initramfs の再生成
sudo dracut -f

# 特定のカーネルバージョン用
sudo dracut -f /boot/initramfs-5.14.0-362.el9.x86_64.img 5.14.0-362.el9.x86_64

# 詳細出力で再生成
sudo dracut -f -v

# 含まれるモジュールの一覧
dracut --list-modules

# 現在の initramfs の内容を表示
lsinitrd /boot/initramfs-$(uname -r).img | head -30

# 特定のモジュールを追加して生成
sudo dracut -f --add "multipath" --add-drivers "dm-multipath"

# dracut 設定ファイル
cat /etc/dracut.conf
# /etc/dracut.conf の設定例

# 追加のドライバ
add_drivers+=" vfio vfio_iommu_type1 vfio_pci vfio_virqfd "

# 追加の dracut モジュール
add_dracutmodules+=" crypt dm lvm "

# 省略するモジュール(不要なものを除外してサイズ削減)
omit_dracutmodules+=" plymouth "

# 圧縮方式
compress="zstd"

# ホスト固有の設定のみを含める
hostonly="yes"

# ファームウェアを含める
install_optional_items+=" /lib/firmware/iwlwifi-*.ucode "

4.4 initramfs のブートプロセスにおける役割

カーネル起動
    ↓
initramfs をメモリに展開(tmpfs としてマウント)
    ↓
/init スクリプトを実行
    ↓
必要なカーネルモジュールのロード(ストレージドライバ等)
    ↓
udev によるデバイスの検出・作成
    ↓
LVM / RAID / LUKS のアセンブル(必要な場合)
    ↓
ルートファイルシステムのマウント(/sysroot または /root)
    ↓
switch_root: initramfs から実際のルートファイルシステムに切り替え
    ↓
/sbin/init(systemd)の実行

4.5 initramfs のトラブルシューティング

# initramfs でシェルに入る(ブート時にカーネルパラメータに追加)
# rd.break                     # switch_root の直前で停止
# rd.break=pre-mount           # マウント前で停止
# rd.break=pre-pivot           # pivot_root 前で停止

# initramfs のデバッグモード
# rd.debug                     # デバッグログを有効化

# initramfs シェルでの操作例(rd.break を使用した場合)
# パスワードリセット
mount -o remount,rw /sysroot
chroot /sysroot
passwd root
touch /.autorelabel  # SELinux を使用している場合
exit
exit
# Ctrl+D で起動を続行

# initramfs に特定のファイルが含まれているか確認
lsinitrd /boot/initramfs-$(uname -r).img | grep -i "lvm"

# initramfs のサイズが大きすぎる場合の対処
# hostonly モードで再生成(必要最小限のモジュールのみ含める)
sudo dracut -f --hostonly

第5章: systemd の基本アーキテクチャ

5.1 systemd の概要

systemd は、Linux システムの初期化とサービス管理を担う統合的なシステムマネージャーである。2010年に Lennart Poettering と Kay Sievers によって開発が開始され、現在ではほぼ全ての主要な Linux ディストリビューションで PID 1(最初のプロセス)として採用されている。

SysV init との比較

特性SysV initsystemd
起動方式逐次実行(シーケンシャル)並列実行(パラレル)
設定形式シェルスクリプト宣言的な Unit ファイル
依存関係数値による起動順序明示的な依存関係定義
サービス監視なし(別途実装が必要)組み込みの監視・自動再起動
リソース制御なしcgroups による統合管理
ログ管理syslog 経由journald による構造化ログ
ソケット活性化inetd 等が別途必要組み込みサポート
起動速度遅い高速

5.2 systemd のアーキテクチャ

+-------------------------------------------------------------------+
|                     systemd エコシステム                             |
+-------------------------------------------------------------------+
|                                                                   |
|  +-----------+  +-----------+  +----------+  +-----------+        |
|  | systemctl |  | journalctl|  | loginctl |  | timedatectl|       |
|  +-----------+  +-----------+  +----------+  +-----------+        |
|  | systemd-  |  | systemd-  |  | systemd- |  | systemd-  |       |
|  | analyze   |  | cat       |  | cgls     |  | cgtop     |       |
|  +-----------+  +-----------+  +----------+  +-----------+        |
|                                                                   |
|  +-------------------------------------------------------------+ |
|  |                    systemd (PID 1)                           | |
|  |  +----------+ +----------+ +----------+ +----------+        | |
|  |  | Service  | | Socket   | | Timer    | | Mount    |        | |
|  |  | Manager  | | Activat. | | Manager  | | Manager  |        | |
|  |  +----------+ +----------+ +----------+ +----------+        | |
|  |  +----------+ +----------+ +----------+ +----------+        | |
|  |  | Device   | | Swap     | | Path     | | Scope    |        | |
|  |  | Manager  | | Manager  | | Monitor  | | Manager  |        | |
|  |  +----------+ +----------+ +----------+ +----------+        | |
|  +-------------------------------------------------------------+ |
|                                                                   |
|  +-------------------------------------------------------------+ |
|  |                  補助デーモン群                                 | |
|  |  +-------------+ +-------------+ +---------------+           | |
|  |  | journald    | | logind      | | resolved      |           | |
|  |  | (ログ管理)   | | (セッション) | | (DNS解決)      |           | |
|  |  +-------------+ +-------------+ +---------------+           | |
|  |  +-------------+ +-------------+ +---------------+           | |
|  |  | networkd    | | timesyncd   | | udevd         |           | |
|  |  | (ネットワーク)| | (NTP同期)   | | (デバイス管理)  |           | |
|  |  +-------------+ +-------------+ +---------------+           | |
|  +-------------------------------------------------------------+ |
|                                                                   |
|  +-------------------------------------------------------------+ |
|  |                    cgroups v2                                 | |
|  |  リソース制御(CPU, メモリ, I/O, ネットワーク)                   | |
|  +-------------------------------------------------------------+ |
|                                                                   |
+-------------------------------------------------------------------+

5.3 systemd の主要コンポーネント

コンポーネント説明設定ファイル
systemd (PID 1)システムマネージャー本体/etc/systemd/system.conf
systemd-journald構造化ログ管理/etc/systemd/journald.conf
systemd-logindユーザーセッション管理/etc/systemd/logind.conf
systemd-networkdネットワーク設定管理/etc/systemd/networkd.conf
systemd-resolvedDNS リゾルバー/etc/systemd/resolved.conf
systemd-timesyncdNTP 時刻同期/etc/systemd/timesyncd.conf
systemd-udevdデバイス管理/etc/udev/rules.d/
systemd-tmpfiles一時ファイル管理/etc/tmpfiles.d/
systemd-sysusersシステムユーザー管理/etc/sysusers.d/
systemd-coredumpコアダンプ管理/etc/systemd/coredump.conf

5.4 systemd の起動プロセス

カーネルから /sbin/init (systemd) が起動
    ↓
/etc/systemd/system.conf の読み込み
    ↓
デフォルトターゲットの決定(default.target)
    ↓
依存関係ツリーの構築
    ↓
Unit の並列起動開始
    ↓
    ├── local-fs.target(ローカルファイルシステムのマウント)
    ├── swap.target(スワップの有効化)
    ├── sysinit.target(システム初期化)
    │   ├── udev のトリガー
    │   ├── /etc/fstab のマウント
    │   └── sysctl の適用
    ├── basic.target(基本サービスの起動)
    │   ├── タイマー
    │   ├── パス監視
    │   └── ソケット
    ├── network.target(ネットワークの設定)
    │   └── NetworkManager / systemd-networkd
    └── multi-user.target / graphical.target
        ├── sshd.service
        ├── crond.service
        ├── httpd.service
        └── その他のサービス
    ↓
default.target 到達(起動完了)

5.5 Unit の種類

systemd では、管理対象を「Unit」という概念で統一的に扱う。

Unit タイプ拡張子説明
Service.serviceデーモンプロセスの管理
Socket.socketソケット活性化の設定
Target.target複数の Unit をグループ化(ランレベルに相当)
Mount.mountファイルシステムのマウント
Automount.automount自動マウントポイント
Swap.swapスワップ領域の管理
Timer.timerタイマーベースの活性化(cron の代替)
Path.pathファイルシステムパスの監視
Device.deviceカーネルデバイスの表現
Slice.slicecgroups ベースのリソースグループ
Scope.scope外部で起動されたプロセスのグループ

5.6 Unit ファイルの配置場所

systemd の Unit ファイルには優先順位がある。

# 優先順位(高 → 低)
# 1. /etc/systemd/system/       - 管理者によるカスタマイズ(最優先)
# 2. /run/systemd/system/       - ランタイムで生成された Unit
# 3. /usr/lib/systemd/system/   - パッケージによりインストールされた Unit

# Unit ファイルの検索パスを確認
systemd-analyze unit-paths

# 特定の Unit ファイルの実際のパスを確認
systemctl show -p FragmentPath sshd.service
# 出力例: FragmentPath=/usr/lib/systemd/system/sshd.service

# 全ての Unit ファイルの場所を一覧
systemctl list-unit-files --type=service

オーバーライドの仕組み(ドロップイン)

既存の Unit ファイルを変更する場合、元のファイルを直接編集するのではなく、ドロップインファイルを使用する。

# systemctl edit でドロップインファイルを作成(推奨)
sudo systemctl edit sshd.service
# → /etc/systemd/system/sshd.service.d/override.conf が作成される

# Unit ファイル全体を上書きする場合
sudo systemctl edit --full sshd.service
# → /etc/systemd/system/sshd.service が作成される

# ドロップインディレクトリの手動作成
sudo mkdir -p /etc/systemd/system/sshd.service.d/
cat << 'EOF' | sudo tee /etc/systemd/system/sshd.service.d/override.conf
[Service]
# 既存のリスタート設定を上書き
Restart=always
RestartSec=5

# メモリ制限の追加
MemoryMax=512M
EOF

# 変更を反映
sudo systemctl daemon-reload

第6章: systemd ターゲットとランレベル

6.1 ターゲットの概念

systemd ターゲットは、SysV init のランレベルに相当する概念であり、システムの状態を定義するための同期点(synchronization point)として機能する。ターゲットは他の Unit をグループ化し、特定のシステム状態を実現するために必要な全てのサービスが起動されていることを保証する。

ランレベルとターゲットの対応表

SysV ランレベルsystemd ターゲット説明
0poweroff.targetシステム停止
1rescue.targetシングルユーザーモード(レスキュー)
2multi-user.targetマルチユーザー(Debian系ではGUI付き)
3multi-user.targetマルチユーザー(テキストモード)
4multi-user.target未使用(カスタム用途)
5graphical.targetグラフィカルモード(GUI)
6reboot.targetシステム再起動
emergencyemergency.target緊急モード(最小限のシェル)

6.2 ターゲットの管理

# 現在のデフォルトターゲットを確認
systemctl get-default
# 出力例: multi-user.target

# デフォルトターゲットの変更
sudo systemctl set-default multi-user.target
# Created symlink /etc/systemd/system/default.target → /lib/systemd/system/multi-user.target

sudo systemctl set-default graphical.target
# Created symlink /etc/systemd/system/default.target → /lib/systemd/system/graphical.target

# 実行中に別のターゲットに切り替え
sudo systemctl isolate rescue.target      # レスキューモードに切り替え
sudo systemctl isolate multi-user.target  # マルチユーザーモードに切り替え
sudo systemctl isolate graphical.target   # グラフィカルモードに切り替え

# システムの停止・再起動
sudo systemctl poweroff   # 電源オフ
sudo systemctl reboot     # 再起動
sudo systemctl halt       # 停止(電源オフしない)
sudo systemctl suspend    # サスペンド
sudo systemctl hibernate  # ハイバネート

6.3 ターゲットの依存関係

# ターゲットの依存関係を表示
systemctl list-dependencies multi-user.target
# 出力例:
# multi-user.target
# ● ├─atd.service
# ● ├─cron.service
# ● ├─dbus.service
# ● ├─networkd-dispatcher.service
# ● ├─rsyslog.service
# ● ├─ssh.service
# ● ├─systemd-ask-password-wall.path
# ● ├─systemd-logind.service
# ● ├─systemd-user-sessions.service
# ● └─basic.target
# ●   ├─-.mount
# ●   ├─tmp.mount
# ●   └─sysinit.target
# ●     ├─dev-hugepages.mount
# ●     ├─dev-mqueue.mount
# ●     └─...

# 逆依存関係(このターゲットを必要とする Unit)
systemctl list-dependencies --reverse multi-user.target

# ターゲットに含まれるサービスの一覧
systemctl list-dependencies --type=service multi-user.target

6.4 ターゲットの依存関係チェーン

                         sysinit.target
                              ↓
                         basic.target
                              ↓
              +---------------+----------------+
              ↓                                ↓
      multi-user.target               graphical.target
              ↓                         (multi-user.target に依存)
      ├── sshd.service
      ├── crond.service
      ├── rsyslog.service
      ├── network.target
      │   └── NetworkManager.service
      └── ...

6.5 カスタムターゲットの作成

# カスタムターゲットの作成例: メンテナンスモード
cat << 'EOF' | sudo tee /etc/systemd/system/maintenance.target
[Unit]
Description=Maintenance Mode Target
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

[Install]
Alias=maintenance.target
EOF

# メンテナンスモード用のサービスを作成
cat << 'EOF' | sudo tee /etc/systemd/system/maintenance-banner.service
[Unit]
Description=Display Maintenance Mode Banner
After=basic.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/maintenance-banner.sh

[Install]
WantedBy=maintenance.target
EOF

# 有効化
sudo systemctl daemon-reload
sudo systemctl enable maintenance-banner.service

# メンテナンスモードに切り替え
sudo systemctl isolate maintenance.target

6.6 rescue.target と emergency.target

rescue.target(レスキューモード)

  • 基本的なシステムが起動している状態
  • ルートファイルシステムがマウント済み
  • ネットワークは未起動
  • root ログインが必要
# ブート時にレスキューモードで起動する方法
# GRUB メニューで 'e' を押し、linux 行に以下を追加:
# systemd.unit=rescue.target
# または
# single
# または
# 1

emergency.target(緊急モード)

  • 最小限のシステムのみ起動
  • ルートファイルシステムは読み取り専用でマウント
  • systemd の依存関係処理を最小限にスキップ
  • ファイルシステムの修復作業等に使用
# ブート時に緊急モードで起動する方法
# GRUB メニューで 'e' を押し、linux 行に以下を追加:
# systemd.unit=emergency.target
# または
# emergency

# 緊急モードでの操作例
# ファイルシステムの修復
fsck /dev/sda2

# ルートファイルシステムを読み書き可能にする
mount -o remount,rw /

# fstab の修正
vi /etc/fstab

# 修正後、読み取り専用に戻して再起動
mount -o remount,ro /
systemctl reboot

第7章: Unit ファイルの詳細

7.1 Unit ファイルの構造

Unit ファイルは INI スタイルの設定ファイルであり、セクションとディレクティブで構成される。

[Unit]
# Unit の基本情報と依存関係

[Service]  # .service の場合
# サービス固有の設定

[Install]
# インストール(有効化/無効化)に関する設定

7.2 [Unit] セクション

[Unit]
# 基本情報
Description=My Application Service
Documentation=https://example.com/docs
Documentation=man:myapp(8)

# === 依存関係(順序制御なし) ===
# Wants: 弱い依存(依存先が失敗してもこの Unit は起動する)
Wants=network-online.target

# Requires: 強い依存(依存先が失敗するとこの Unit も失敗する)
Requires=postgresql.service

# Requisite: 事前に起動済みであることを要求(未起動なら即座に失敗)
Requisite=basic.target

# BindsTo: 最も強い依存(依存先が停止するとこの Unit も停止する)
BindsTo=dev-sda1.device

# PartOf: 依存先が停止・再起動するとこの Unit も停止・再起動
PartOf=network.target

# Conflicts: 排他関係(同時に起動できない)
Conflicts=iptables.service

# === 順序制御 ===
# After: この Unit はリストされた Unit の「後に」起動する
After=network-online.target postgresql.service

# Before: この Unit はリストされた Unit の「前に」起動する
Before=httpd.service

# === 条件と制約 ===
# 条件が満たされない場合、Unit の起動をスキップ(失敗にはならない)
ConditionPathExists=/etc/myapp/config.yml
ConditionFileNotEmpty=/etc/myapp/config.yml
ConditionDirectoryNotEmpty=/var/lib/myapp
ConditionKernelVersion=>=5.10
ConditionVirtualization=!container
ConditionMemory=>=2G
ConditionCPUs=>=2
ConditionUser=myapp
ConditionGroup=myapp
ConditionACPower=true

# Assert は条件が満たされない場合にエラーを発生させる
AssertPathExists=/etc/myapp/config.yml

# 起動失敗時のアクション
OnFailure=notify-admin@%n.service
OnSuccess=cleanup@%n.service

# 起動レート制限
StartLimitIntervalSec=60
StartLimitBurst=5
StartLimitAction=reboot-force  # none, reboot, reboot-force, reboot-immediate, poweroff, exit

7.3 [Service] セクション

[Service]
# === サービスタイプ ===
# simple:  ExecStart のプロセスがメインプロセス(デフォルト)
# forking: ExecStart がフォークして親プロセスが終了する(伝統的デーモン)
# oneshot: 一回実行して終了するタスク
# dbus:    D-Bus 名の取得で起動完了と判定
# notify:  sd_notify() で起動完了を通知
# idle:    全てのジョブが完了してから起動
Type=notify

# PIDファイル(forking タイプで使用)
# PIDFile=/run/myapp/myapp.pid

# === 実行設定 ===
ExecStartPre=/usr/local/bin/myapp-check-config
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml
ExecStartPost=/usr/local/bin/myapp-post-start
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/usr/local/bin/myapp --shutdown
ExecStopPost=/usr/local/bin/myapp-cleanup

# '-' プレフィクス: コマンドが失敗してもエラーにしない
ExecStartPre=-/usr/local/bin/myapp-optional-check

# === 再起動設定 ===
Restart=on-failure
# no:         再起動しない
# on-success: 正常終了時のみ再起動
# on-failure: 異常終了時のみ再起動(推奨)
# on-abnormal: シグナルまたはタイムアウト時に再起動
# on-watchdog: ウォッチドッグタイムアウト時のみ再起動
# on-abort:   キャッチされないシグナルで終了時に再起動
# always:     常に再起動

RestartSec=5                # 再起動間隔(秒)
RestartSteps=5              # 段階的な再起動間隔増加
RestartMaxDelaySec=60       # 最大再起動間隔

# 特定の終了コードでは再起動しない
RestartPreventExitStatus=23 SIGTERM
# 特定の終了コードのみ再起動する
RestartForceExitStatus=7 SIGKILL

# === タイムアウト ===
TimeoutStartSec=90          # 起動タイムアウト
TimeoutStopSec=90           # 停止タイムアウト
TimeoutSec=90               # 起動・停止両方のタイムアウト
WatchdogSec=30              # ウォッチドッグタイムアウト(sd_notify で定期的に通知が必要)

# === ユーザー・グループ ===
User=myapp
Group=myapp
DynamicUser=yes             # 一時的なユーザーを自動作成

# === 環境変数 ===
Environment="NODE_ENV=production" "PORT=8080"
EnvironmentFile=/etc/myapp/env
EnvironmentFile=-/etc/myapp/env.local  # '-' で存在しなくてもエラーにしない

# === 作業ディレクトリ ===
WorkingDirectory=/opt/myapp
RootDirectory=/opt/myapp-chroot

# === リソース制限 ===
LimitNOFILE=65536           # ファイルディスクリプタ数
LimitNPROC=4096             # プロセス数
LimitCORE=infinity          # コアダンプサイズ
LimitMEMLOCK=infinity       # ロック可能メモリ
MemoryMax=1G                # メモリ上限(cgroups)
CPUQuota=200%               # CPU クォータ(200% = 2コア分)
IOWeight=100                # I/O ウェイト

# === セキュリティ ===
NoNewPrivileges=yes         # 権限昇格を禁止
ProtectSystem=strict        # / を読み取り専用にマウント
ProtectHome=yes             # /home を空のディレクトリとしてマウント
PrivateTmp=yes              # /tmp を隔離
PrivateDevices=yes          # デバイスアクセスを制限
ProtectKernelTunables=yes   # /proc/sys 等を読み取り専用
ProtectKernelModules=yes    # カーネルモジュールのロードを禁止
ProtectControlGroups=yes    # cgroup を読み取り専用
ReadWritePaths=/var/lib/myapp /var/log/myapp
ReadOnlyPaths=/etc/myapp
CapabilityBoundingSet=CAP_NET_BIND_SERVICE  # 許可する capability
AmbientCapabilities=CAP_NET_BIND_SERVICE
SystemCallFilter=@system-service  # 許可するシステムコール
SystemCallArchitectures=native    # 許可するアーキテクチャ

# === プロセス管理 ===
KillMode=mixed              # control-group, process, mixed, none
KillSignal=SIGTERM
FinalKillSignal=SIGKILL
SendSIGHUP=yes
SendSIGKILL=yes

# === 標準出力・エラー ===
StandardOutput=journal      # inherit, null, tty, journal, syslog, kmsg, socket
StandardError=journal
SyslogIdentifier=myapp
SyslogFacility=daemon

7.4 [Install] セクション

[Install]
# サービスが有効化されたときにリンクを作成するターゲット
WantedBy=multi-user.target

# 強い依存関係でリンクを作成
RequiredBy=critical-app.target

# エイリアスの設定
Alias=myapp.service

# 特定のサービスの代わりとして設定
Also=myapp-cleanup.timer
Also=myapp-logrotate.timer

7.5 Unit ファイルのテンプレート

テンプレートを使うと、パラメータ化された Unit を複数のインスタンスとして起動できる。

# テンプレートファイル: myapp@.service(@ がテンプレートの目印)
cat << 'EOF' | sudo tee /etc/systemd/system/myapp@.service
[Unit]
Description=My Application Instance %i
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
Environment="INSTANCE=%i"
Environment="PORT=%i"
ExecStart=/usr/local/bin/myapp --port %i --config /etc/myapp/%i.yml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

テンプレートで使用可能な Specifier:

Specifier説明
%iインスタンス名(エスケープ解除済み)8080
%Iインスタンス名(エスケープ済み)8080
%n完全な Unit 名myapp@8080.service
%N完全な Unit 名(エスケープ解除済み)myapp@8080.service
%pUnit のプレフィクス名myapp
%PUnit のプレフィクス名(エスケープ解除済み)myapp
%fインスタンス名を / で始まるパスに変換/8080
%Hホスト名server01
%mマシンIDabc123...
%tランタイムディレクトリ/run(system), /run/user/1000(user)
%%リテラルの %%
# テンプレートからインスタンスを起動
sudo systemctl start myapp@8080.service
sudo systemctl start myapp@8081.service
sudo systemctl start myapp@8082.service

# インスタンスの有効化
sudo systemctl enable myapp@8080.service
sudo systemctl enable myapp@8081.service

# 全インスタンスの状態確認
systemctl status "myapp@*.service"

7.6 実践的な Unit ファイル例

Go アプリケーションの Service Unit

# /etc/systemd/system/go-api.service
[Unit]
Description=Go API Server
Documentation=https://github.com/example/go-api
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service

[Service]
Type=notify
User=goapi
Group=goapi

# 環境変数
EnvironmentFile=/etc/go-api/env
Environment="GOMAXPROCS=4"

# 実行
ExecStartPre=/usr/local/bin/go-api --validate-config
ExecStart=/usr/local/bin/go-api serve --config /etc/go-api/config.yaml
ExecReload=/bin/kill -USR2 $MAINPID

# 再起動ポリシー
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60
StartLimitBurst=3

# リソース
LimitNOFILE=65536
MemoryMax=2G
CPUQuota=400%

# セキュリティ
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/go-api /var/log/go-api

# グレースフルシャットダウン
KillSignal=SIGTERM
TimeoutStopSec=30

# ウォッチドッグ
WatchdogSec=30

[Install]
WantedBy=multi-user.target

ワンショット(初期化スクリプト)の Unit

# /etc/systemd/system/app-init.service
[Unit]
Description=Application Initialization
After=network-online.target
ConditionPathExists=!/var/lib/app/.initialized

[Service]
Type=oneshot
RemainAfterExit=yes
User=app
ExecStart=/usr/local/bin/app-initialize
ExecStartPost=/bin/touch /var/lib/app/.initialized

[Install]
WantedBy=multi-user.target

第8章: systemctl コマンド体系

8.1 サービス管理の基本コマンド

# === サービスの起動・停止・再起動 ===
sudo systemctl start   httpd.service    # サービスの起動
sudo systemctl stop    httpd.service    # サービスの停止
sudo systemctl restart httpd.service    # サービスの再起動
sudo systemctl reload  httpd.service    # 設定の再読み込み(プロセスは再起動しない)
sudo systemctl try-restart httpd.service  # 起動中の場合のみ再起動
sudo systemctl reload-or-restart httpd.service  # reload 可能なら reload、そうでなければ restart
sudo systemctl kill httpd.service       # プロセスにシグナルを送信
sudo systemctl kill -s SIGUSR1 httpd.service  # 特定のシグナルを送信

# .service サフィックスは省略可能
sudo systemctl start httpd
sudo systemctl stop httpd

# === 自動起動の有効化・無効化 ===
sudo systemctl enable  httpd.service    # 自動起動を有効化
sudo systemctl disable httpd.service    # 自動起動を無効化
sudo systemctl enable --now httpd.service  # 有効化と同時に起動
sudo systemctl disable --now httpd.service # 無効化と同時に停止
sudo systemctl reenable httpd.service   # 再有効化(リンクの再作成)

# === サービスのマスク(完全な無効化) ===
sudo systemctl mask   httpd.service     # マスク(一切起動不可にする)
sudo systemctl unmask httpd.service     # マスク解除
# マスクすると /dev/null へのシンボリックリンクが作成される

8.2 状態確認コマンド

# === サービスの状態確認 ===
systemctl status httpd.service
# 出力例:
# ● httpd.service - The Apache HTTP Server
#      Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
#      Active: active (running) since Thu 2024-03-21 10:00:00 JST; 2h 30min ago
#        Docs: man:httpd.service(8)
#    Main PID: 1234 (httpd)
#      Status: "Total requests: 1000; Idle/Busy workers 100/0;..."
#       Tasks: 213 (limit: 4915)
#      Memory: 45.2M
#         CPU: 1.234s
#      CGroup: /system.slice/httpd.service
#              ├─1234 /usr/sbin/httpd -DFOREGROUND
#              ├─1235 /usr/sbin/httpd -DFOREGROUND
#              └─1236 /usr/sbin/httpd -DFOREGROUND
#
# Mar 21 10:00:00 server01 systemd[1]: Starting The Apache HTTP Server...
# Mar 21 10:00:01 server01 httpd[1234]: Server configured, listening on: port 443, port 80
# Mar 21 10:00:01 server01 systemd[1]: Started The Apache HTTP Server.

# 簡潔な状態確認
systemctl is-active httpd.service       # active / inactive
systemctl is-enabled httpd.service      # enabled / disabled
systemctl is-failed httpd.service       # failed / active

# === Unit の一覧表示 ===
# ロードされた Unit の一覧
systemctl list-units
systemctl list-units --type=service
systemctl list-units --type=service --state=running
systemctl list-units --type=service --state=failed

# インストールされた Unit ファイルの一覧
systemctl list-unit-files
systemctl list-unit-files --type=service
systemctl list-unit-files --state=enabled

# 失敗した Unit の一覧
systemctl --failed
systemctl list-units --state=failed

# === 依存関係の確認 ===
systemctl list-dependencies httpd.service
systemctl list-dependencies --reverse httpd.service  # 逆依存
systemctl list-dependencies --before httpd.service   # この Unit の前に起動する Unit
systemctl list-dependencies --after httpd.service    # この Unit の後に起動する Unit

# === Unit のプロパティ確認 ===
systemctl show httpd.service
systemctl show httpd.service -p MainPID
systemctl show httpd.service -p MainPID,ActiveState,SubState

# === ジョブの確認 ===
systemctl list-jobs  # 実行中のジョブ一覧

8.3 システム管理コマンド

# === daemon-reload ===
# Unit ファイルの変更を systemd に認識させる(重要!)
sudo systemctl daemon-reload

# === システムの状態変更 ===
sudo systemctl reboot                  # 再起動
sudo systemctl poweroff                # 電源オフ
sudo systemctl halt                    # 停止
sudo systemctl suspend                 # サスペンド
sudo systemctl hibernate               # ハイバネート
sudo systemctl hybrid-sleep            # ハイブリッドスリープ

# === 緊急時のコマンド ===
sudo systemctl rescue                  # レスキューモードへ
sudo systemctl emergency               # 緊急モードへ

# === daemon の再実行 ===
sudo systemctl daemon-reexec           # systemd 自体を再実行(PID 1のアップグレード)

8.4 cgroup とリソース管理

# === cgroup ツリーの確認 ===
systemd-cgls
# 出力例:
# Control group /:
# -.slice
# ├─init.scope
# │ └─1 /sbin/init
# ├─system.slice
# │ ├─sshd.service
# │ │ └─1234 sshd: /usr/sbin/sshd -D
# │ ├─httpd.service
# │ │ ├─2345 /usr/sbin/httpd -DFOREGROUND
# │ │ └─2346 /usr/sbin/httpd -DFOREGROUND
# │ └─...
# └─user.slice
#   └─user-1000.slice
#     └─session-1.scope
#       └─3456 -bash

# cgroup ごとのリソース使用量をリアルタイム表示
systemd-cgtop
# 出力例:
# Control Group           Tasks   %CPU   Memory  Input/s Output/s
# /                         234    5.2     1.2G        -        -
# /system.slice              45    3.1   256.0M        -        -
# /system.slice/httpd.se...  10    2.0   128.0M        -        -
# /user.slice                20    1.5   512.0M        -        -

# === リソース制限の確認 ===
systemctl show httpd.service -p MemoryMax,CPUQuota,IOWeight

# === 実行時のリソース制限変更 ===
sudo systemctl set-property httpd.service MemoryMax=1G
sudo systemctl set-property httpd.service CPUQuota=200%
sudo systemctl set-property httpd.service IOWeight=200

# 一時的な変更(再起動で元に戻る)
sudo systemctl set-property --runtime httpd.service MemoryMax=2G

8.5 スライス(Slice)によるリソースの階層管理

# スライスの構造
# -.slice(ルートスライス)
# ├── system.slice(システムサービス)
# ├── user.slice(ユーザーセッション)
# │   ├── user-1000.slice
# │   └── user-1001.slice
# └── machine.slice(仮想マシン・コンテナ)

# カスタムスライスの作成
cat << 'EOF' | sudo tee /etc/systemd/system/highpriority.slice
[Unit]
Description=High Priority Services Slice
Before=slices.target

[Slice]
MemoryMax=4G
CPUWeight=200
IOWeight=200
EOF

# サービスをカスタムスライスに配置
cat << 'EOF' | sudo tee /etc/systemd/system/httpd.service.d/slice.conf
[Service]
Slice=highpriority.slice
EOF

sudo systemctl daemon-reload
sudo systemctl restart httpd.service

# スライスの状態確認
systemctl status highpriority.slice

第9章: systemd ジャーナル(journald)

9.1 journald の概要

systemd-journald は、systemd に統合されたログ管理デーモンである。構造化されたバイナリ形式でログを保存し、高速な検索とフィルタリングを提供する。

9.2 journald の設定

# /etc/systemd/journald.conf の設定例
cat /etc/systemd/journald.conf
[Journal]
# ログの永続化設定
# volatile:    /run/log/journal/ のみ(揮発性)
# persistent:  /var/log/journal/ に永続保存
# auto:        /var/log/journal/ が存在すれば永続(デフォルト)
# none:        ログを保存しない
Storage=persistent

# ログの圧縮
Compress=yes

# シール(前方安全なシーリング)
Seal=yes

# ジャーナルファイルの分割
SplitMode=uid

# ディスク使用量の制限
SystemMaxUse=2G           # 永続ジャーナルの最大サイズ
SystemKeepFree=4G         # 最低限の空き容量
SystemMaxFileSize=128M    # 個別ファイルの最大サイズ
SystemMaxFiles=100        # 最大ファイル数

RuntimeMaxUse=256M        # 揮発性ジャーナルの最大サイズ
RuntimeKeepFree=256M      # ランタイム領域の空き容量
RuntimeMaxFileSize=32M    # ランタイム個別ファイルの最大サイズ

# ログの保持期間
MaxRetentionSec=1month    # 最大保持期間
MaxFileSec=1week          # 個別ファイルの最大保持期間

# レート制限
RateLimitIntervalSec=30s  # レート制限の間隔
RateLimitBurst=10000      # 間隔内の最大メッセージ数

# syslog への転送
ForwardToSyslog=yes
ForwardToKMsg=no
ForwardToConsole=no
ForwardToWall=yes

# 最大ログレベル
MaxLevelStore=debug       # 保存する最大レベル
MaxLevelSyslog=debug      # syslog へ転送する最大レベル
MaxLevelKMsg=notice       # kmsg へ転送する最大レベル
MaxLevelConsole=info      # コンソールへ出力する最大レベル
MaxLevelWall=emerg        # wall メッセージの最大レベル
# ジャーナルの永続化(/var/log/journal/ の作成)
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal

# journald の再起動
sudo systemctl restart systemd-journald

9.3 journalctl コマンド

# === 基本的なログ閲覧 ===
journalctl                     # 全てのログ
journalctl -b                  # 現在のブートのログ
journalctl -b -1               # 前回のブートのログ
journalctl --list-boots         # ブートの一覧
journalctl -f                  # リアルタイム表示(tail -f 相当)
journalctl -n 50               # 最新 50 行
journalctl --no-pager          # ページャーなし

# === Unit によるフィルタ ===
journalctl -u sshd.service                # 特定のサービスのログ
journalctl -u sshd.service -u httpd.service  # 複数サービス
journalctl -u "myapp@*.service"            # テンプレートインスタンス

# === 時間によるフィルタ ===
journalctl --since "2024-03-21 10:00:00"
journalctl --until "2024-03-21 12:00:00"
journalctl --since "1 hour ago"
journalctl --since "2024-03-20" --until "2024-03-21"
journalctl --since today
journalctl --since yesterday --until today

# === 優先度によるフィルタ ===
journalctl -p err              # エラー以上
journalctl -p warning          # 警告以上
journalctl -p 0..3             # emerg(0) から err(3) まで
# 優先度: emerg(0), alert(1), crit(2), err(3), warning(4), notice(5), info(6), debug(7)

# === フィールドによるフィルタ ===
journalctl _PID=1234           # PID で絞り込み
journalctl _UID=1000           # ユーザー ID で絞り込み
journalctl _COMM=sshd          # コマンド名で絞り込み
journalctl _HOSTNAME=server01  # ホスト名で絞り込み
journalctl _TRANSPORT=kernel   # カーネルメッセージ
journalctl SYSLOG_FACILITY=10  # 特定のファシリティ

# 利用可能なフィールドの一覧
journalctl --fields

# フィールドの値の一覧
journalctl -F _COMM
journalctl -F SYSLOG_IDENTIFIER

# === 出力形式 ===
journalctl -o short            # デフォルト(syslog 風)
journalctl -o short-iso        # ISO 8601 日付形式
journalctl -o short-precise    # マイクロ秒精度
journalctl -o verbose          # 全フィールド表示
journalctl -o json             # JSON 形式
journalctl -o json-pretty      # JSON(整形済み)
journalctl -o cat              # メッセージのみ
journalctl -o export           # バイナリエクスポート形式

# === ディスク使用量 ===
journalctl --disk-usage
# 出力例: Archived and active journals take up 1.2G in the file system.

# ジャーナルの掃除
sudo journalctl --vacuum-size=500M   # 500MB まで縮小
sudo journalctl --vacuum-time=30d    # 30日以前を削除
sudo journalctl --vacuum-files=5     # 最新5ファイルのみ保持

# === カーネルログ ===
journalctl -k                  # カーネルメッセージ(dmesg 相当)
journalctl -k -b -1            # 前回ブートのカーネルメッセージ

# === grep との組み合わせ ===
journalctl -u sshd --no-pager | grep "Failed password"
journalctl -u sshd -g "Failed password"  # 組み込みの grep(-g オプション)

第10章: タイマーとスケジューリング

10.1 systemd タイマーの概要

systemd タイマーは、cron に代わるタスクスケジューリングメカニズムである。

cron との比較

特性cronsystemd timer
ログsyslog(分散)journald(統合)
依存関係なしsystemd の依存関係管理
リソース制御なしcgroups 統合
実行漏れ停止中は実行されないPersistent=yes で対応可能
精度分単位マイクロ秒単位
ランダム遅延なしRandomizedDelaySec
セキュリティ限定的サンドボックス設定可
デバッグ困難systemctl / journalctl

10.2 タイマー Unit の作成

Monotonic タイマー(起動後の経過時間ベース)

# /etc/systemd/system/myapp-health.timer
[Unit]
Description=My Application Health Check Timer

[Timer]
# ブート後 5 分で最初の実行
OnBootSec=5min

# 前回の実行完了後 30 秒ごと
OnUnitActiveSec=30s

# 精度(デフォルトは 1min、正確なタイミングが必要な場合は短くする)
AccuracySec=1s

[Install]
WantedBy=timers.target

Realtime タイマー(カレンダーベース)

# /etc/systemd/system/myapp-backup.timer
[Unit]
Description=Daily Backup Timer

[Timer]
# カレンダー表記
OnCalendar=*-*-* 02:00:00          # 毎日 2:00
# OnCalendar=Mon..Fri *-*-* 09:00:00  # 平日 9:00
# OnCalendar=*-*-01 00:00:00          # 毎月1日 0:00
# OnCalendar=weekly                     # 毎週月曜 0:00
# OnCalendar=daily                      # 毎日 0:00
# OnCalendar=hourly                     # 毎時 0分
# OnCalendar=*:0/15                     # 15分ごと
# OnCalendar=Sat *-*-* 10:00:00        # 毎週土曜 10:00

# ランダム遅延(負荷分散に有効)
RandomizedDelaySec=30min

# 停止中に実行漏れがあった場合、次回起動時に即座に実行
Persistent=true

# 精度
AccuracySec=1s

[Install]
WantedBy=timers.target

対応する Service Unit

# /etc/systemd/system/myapp-backup.service
[Unit]
Description=Daily Backup Service

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup.sh
Nice=10
IOSchedulingClass=idle
# カレンダー表記のテスト
systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
# 出力例:
#   Original form: Mon..Fri *-*-* 09:00:00
# Normalized form: Mon..Fri *-*-* 09:00:00
#     Next elapse: Mon 2024-03-25 09:00:00 JST
#        (in UTC): Mon 2024-03-25 00:00:00 UTC
#        From now: 3 days left

systemd-analyze calendar "*:0/15"
# 15分ごとのスケジュール

# タイマーの管理
sudo systemctl enable --now myapp-backup.timer
sudo systemctl list-timers
sudo systemctl list-timers --all

# タイマーの次回実行時刻を確認
systemctl list-timers
# 出力例:
# NEXT                         LEFT          LAST                         PASSED       UNIT                  ACTIVATES
# Thu 2024-03-21 14:00:00 JST  30min left    Thu 2024-03-21 13:00:00 JST  30min ago    logrotate.timer       logrotate.service
# Fri 2024-03-22 02:00:00 JST  12h left      Thu 2024-03-21 02:00:15 JST  11h ago      myapp-backup.timer    myapp-backup.service

第11章: ブートプロセスのトラブルシューティング

11.1 systemd-analyze による起動分析

# === 起動時間の概要 ===
systemd-analyze
# 出力例:
# Startup finished in 3.123s (firmware) + 1.234s (loader) + 2.345s (kernel)
#   + 5.678s (userspace) = 12.380s
# graphical.target reached after 5.432s in userspace.

# === 各 Unit の起動時間(遅い順) ===
systemd-analyze blame
# 出力例:
#   3.234s NetworkManager-wait-online.service
#   1.567s systemd-journal-flush.service
#   1.234s cloud-init-local.service
#   0.987s cloud-init.service
#   0.567s snapd.service
#   ...

# === クリティカルチェーン(起動のボトルネック) ===
systemd-analyze critical-chain
# 出力例:
# graphical.target @5.432s
# └─multi-user.target @5.430s
#   └─httpd.service @4.500s +0.930s
#     └─network-online.target @4.498s
#       └─NetworkManager-wait-online.service @1.234s +3.264s
#         └─NetworkManager.service @1.000s +0.234s
#           └─basic.target @0.998s
#             └─sockets.target @0.997s
#               └─dbus.socket @0.996s
#                 └─sysinit.target @0.995s

# 特定の Unit のクリティカルチェーン
systemd-analyze critical-chain httpd.service

# === SVG チャートの生成 ===
systemd-analyze plot > /tmp/boot-chart.svg
# ブラウザで表示: firefox /tmp/boot-chart.svg

# === Unit 間の依存関係グラフ ===
systemd-analyze dot --to-pattern='*.target' | dot -Tsvg > /tmp/targets.svg

# === セキュリティ監査 ===
systemd-analyze security
# 出力例:
# UNIT                      EXPOSURE PREDICATE HAPPY
# httpd.service             9.2      UNSAFE    😨
# sshd.service              9.6      UNSAFE    😨
# dbus.service              9.8      UNSAFE    😨

# 特定サービスのセキュリティ詳細
systemd-analyze security httpd.service

# === Unit ファイルの検証 ===
systemd-analyze verify /etc/systemd/system/myapp.service

11.2 一般的なブート問題と解決策

問題1: GRUB がロードされない

# 症状: ブート時に "No bootable device found" または "Operating system not found"

# 原因と解決策:
# 1. MBR/ESP が破損している
#    → ライブ USB から起動して GRUB を再インストール
sudo mount /dev/sda2 /mnt
sudo mount /dev/sda1 /mnt/boot/efi
for dir in dev proc sys; do sudo mount --bind /$dir /mnt/$dir; done
sudo chroot /mnt
grub-install /dev/sda  # BIOS
grub-install --target=x86_64-efi --efi-directory=/boot/efi  # UEFI
update-grub
exit

# 2. BIOS/UEFI のブート順序が正しくない
#    → BIOS/UEFI 設定画面でブート順序を確認

# 3. EFI ブートエントリが消えた
sudo efibootmgr -v  # 確認
sudo efibootmgr --create --disk /dev/sda --part 1 \
  --loader /EFI/ubuntu/shimx64.efi --label "Ubuntu"

問題2: カーネルパニック

# 症状: "Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)"

# 原因と解決策:
# 1. initramfs にルートデバイスのドライバが含まれていない
sudo dracut -f --add-drivers "nvme ahci"
# または
sudo update-initramfs -u

# 2. root= パラメータが正しくない
# GRUB で 'e' を押して linux 行の root= を確認
# UUID を確認:
blkid

# 3. ルートファイルシステムが破損している
# レスキューモードで起動して fsck を実行
fsck -y /dev/sda2

問題3: サービスの起動失敗

# 失敗したサービスの確認
systemctl --failed

# サービスの詳細状態
systemctl status failed-service.service

# ジャーナルでのエラー確認
journalctl -u failed-service.service -b --no-pager

# 依存関係の問題を確認
systemctl list-dependencies failed-service.service
systemd-analyze verify /etc/systemd/system/failed-service.service

# サービスの手動起動でデバッグ
sudo -u serviceuser /path/to/service --debug

問題4: ブートが途中で停止する

# 原因の特定:
# 1. ブート時に Esc キーまたは起動パラメータから quiet を削除して詳細表示

# 2. 前回のブートログを確認
journalctl -b -1 -p err

# 3. 起動の依存関係で循環がないか確認
systemd-analyze verify --recursive-errors=no default.target

# 4. fstab のエントリが問題を起こしていないか確認
# fstab に nofail オプションを追加してテスト
# /etc/fstab の例:
# UUID=xxx /data ext4 defaults,nofail 0 2
# nofail: マウントに失敗しても起動を続行する

問題5: 緊急モードに落ちる

# 症状: "Welcome to emergency mode!" と表示される

# 主な原因:
# 1. /etc/fstab のエントリに問題がある
mount -o remount,rw /
vi /etc/fstab
# 問題のあるエントリをコメントアウトまたは修正
# nofail オプションの追加を検討

# 2. ファイルシステムが破損している
fsck -y /dev/sda2

# 3. systemd generator がエラーを起こしている
systemctl list-units --state=failed
journalctl -b -p err

11.3 デバッグ用カーネルパラメータ

# GRUB メニューで 'e' キーを押し、linux 行に以下を追加してデバッグ

# systemd のデバッグ出力を有効化
systemd.log_level=debug systemd.log_target=kmsg

# 起動時のシェルに入る
init=/bin/bash

# systemd の特定のターゲットまでで停止
systemd.unit=rescue.target
systemd.unit=emergency.target

# initramfs でシェルに入る
rd.break
rd.break=pre-mount

# ネットワーク関連のデバッグ
rd.debug

# SELinux を一時的に無効化(SELinux が原因の場合)
selinux=0
enforcing=0

# ファイルシステムチェックを強制
fsck.mode=force

# Plymouth(スプラッシュスクリーン)を無効化してメッセージを表示
plymouth.enable=0

第12章: 高度な設定とベストプラクティス

12.1 ソケット活性化(Socket Activation)

ソケット活性化は、サービスがソケットへの接続を受けるまでサービスプロセスを起動しない仕組みである。

# /etc/systemd/system/myapp.socket
[Unit]
Description=My Application Socket

[Socket]
ListenStream=8080
# ListenStream=/run/myapp/myapp.sock  # UNIX ソケットの場合
Accept=no           # no: 1つのサービスインスタンスに全接続を渡す
                    # yes: 接続ごとに新しいサービスインスタンスを起動
MaxConnections=256
KeepAlive=yes
NoDelay=yes

# バックログ
Backlog=128

# バッファサイズ
ReceiveBuffer=1M
SendBuffer=1M

[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
Requires=myapp.socket

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp
# ソケット活性化の場合、サービスはファイルディスクリプタ 3 からソケットを受け取る
# ソケット活性化の有効化
sudo systemctl enable --now myapp.socket

# ソケットの状態確認
systemctl status myapp.socket
systemctl list-sockets

12.2 systemd-networkd による ネットワーク設定

# /etc/systemd/network/10-static.network
[Match]
Name=eth0

[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
Domains=example.com

[Route]
Gateway=192.168.1.1
Destination=10.0.0.0/8
# /etc/systemd/network/20-dhcp.network
[Match]
Name=eth1

[Network]
DHCP=yes

[DHCPv4]
UseDNS=yes
UseNTP=yes
UseDomains=yes
RouteMetric=100
# networkd の有効化
sudo systemctl enable --now systemd-networkd
sudo systemctl enable --now systemd-resolved

# ネットワーク状態の確認
networkctl list
networkctl status eth0

12.3 systemd-resolved による DNS 設定

# /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 8.8.4.4
FallbackDNS=1.1.1.1 1.0.0.1
Domains=~example.com
DNSSEC=allow-downgrade
DNSOverTLS=opportunistic
Cache=yes
DNSStubListener=yes
# resolved の状態確認
resolvectl status
resolvectl query example.com
resolvectl statistics

# DNS キャッシュのフラッシュ
resolvectl flush-caches

12.4 systemd-tmpfiles による一時ファイル管理

# /etc/tmpfiles.d/myapp.conf
# Type  Path                    Mode  Owner Group  Age  Argument
d       /run/myapp              0755  myapp myapp  -    -
d       /var/log/myapp          0750  myapp myapp  -    -
f       /var/log/myapp/app.log  0640  myapp myapp  -    -
D       /tmp/myapp-cache        0700  myapp myapp  1d   -
L+      /var/run/myapp.sock     -     -     -      -    /run/myapp/myapp.sock
# z: パーミッションの修正のみ(ファイル作成はしない)
z       /dev/mydevice           0660  root  myapp  -    -
# tmpfiles の手動実行
sudo systemd-tmpfiles --create /etc/tmpfiles.d/myapp.conf
sudo systemd-tmpfiles --clean   # 期限切れファイルの削除
sudo systemd-tmpfiles --remove  # 定義されたパスの削除

12.5 セキュリティベストプラクティス

# サービスのセキュリティ強化テンプレート
cat << 'EOF' | sudo tee /etc/systemd/system/secure-template@.service.d/security.conf
[Service]
# 権限昇格の禁止
NoNewPrivileges=yes

# ファイルシステムの保護
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes

# カーネルの保護
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes

# その他の保護
ProtectControlGroups=yes
ProtectHostname=yes
ProtectClock=yes

# ネットワークの制限(必要に応じて)
# PrivateNetwork=yes
# RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# システムコールの制限
SystemCallFilter=@system-service
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM

# メモリの保護
MemoryDenyWriteExecute=yes

# 実行パスの制限
LockPersonality=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
EOF

12.6 パフォーマンスチューニング

# 不要なサービスの無効化
sudo systemctl disable --now bluetooth.service
sudo systemctl disable --now cups.service
sudo systemctl disable --now avahi-daemon.service
sudo systemctl mask bluetooth.service  # 完全に無効化

# 起動の並列度を調整
# /etc/systemd/system.conf
# [Manager]
# DefaultTasksMax=4096
# DefaultLimitNOFILE=65536

# 起動時間の最適化
# 1. 不要なサービスの無効化
systemd-analyze blame | head -20

# 2. ネットワーク待機の最適化
sudo systemctl disable NetworkManager-wait-online.service

# 3. fsck の最適化
# /etc/fstab で最後のフィールド(pass)を適切に設定
# ルート: 1, その他: 2 または 0(スキップ)

まとめ

本記事では、Linux ブートプロセスと systemd の全容を 12 章にわたって解説した。

起動プロセスの全体像

ファームウェア(BIOS/UEFI) → GRUB2 → カーネル → initramfs → systemd → サービス起動

重要なポイント

  1. ファームウェア: UEFI が主流。Secure Boot によるセキュリティ強化を理解する
  2. GRUB2: /etc/default/grub で設定、grub-mkconfig で反映。修復手順を習得する
  3. カーネル: カーネルパラメータにより動作を制御。トラブルシューティングに必須
  4. initramfs: ルートファイルシステムのマウントに必要なドライバを提供する一時的なファイルシステム
  5. systemd: 宣言的な Unit ファイルで全てのシステムリソースを統一管理
  6. ターゲット: ランレベルに相当する同期点。rescue/emergency を使いこなす
  7. Unit ファイル: テンプレート、ドロップイン、セキュリティ設定を活用する
  8. systemctl: サービスの管理、リソース制御、cgroup 管理の中心
  9. journald: 構造化ログによる高度な検索・フィルタリング
  10. タイマー: cron に代わるスケジューリング機構
  11. トラブルシューティング: systemd-analyzejournalctl を駆使する
  12. セキュリティ: サンドボックス設定によるサービスの保護

参考資料