第3章 システムの初期化

目次

3.1. ブートストラッププロセスの概要
3.1.1. 1段目: UEFI
3.1.2. 2段目: ブートローダー
3.1.3. 3段目: ミニ Debian システム
3.1.4. 4段目: 普通の Debian システム
3.2. Systemd
3.2.1. Systemd init
3.2.2. Systemd login
3.3. カーネルメッセージ
3.4. システムメッセージ
3.5. システム管理
3.6. 他のシステムモニター
3.7. システム設定
3.7.1. ホスト名
3.7.2. ファイルシステム
3.7.3. ネットワークインターフェースの初期化
3.7.4. クラウドシステムの初期化
3.7.5. sshd サービスを調整するカスタム化例
3.8. udev システム
3.9. カーネルモジュール初期化

Debian システムが以下に起動され設定されるかの知っていることはシステム管理者として賢明です。正確で詳細な情報がインストールされたパッケージのソースや文書中にあるとは言え、我々の大部分にとってはちょっと大変過ぎます。

Debian システム初期化の大まかな概要をここに記します。Debian システムは動くターゲットなので、最新のドキュメンテーションを参照する必要があります。

コンピューターシステムは、電源投入イベントからユーザーに機能の完備したオペレーティングシステム (OS) を提供するまでブートストラッププロセスを数段通過します。

単純化のため、デフォールトのインストールをした典型的な PC プラットフォームに限定し議論します。

典型的なブートストラッププロセスは4段ロケットのようです。各段のロケットは次段のロケットにシステムのコントロールを引き継ぎます。

もちろん、これらに関して異なる設定をすることはできます。例えば、自分自身で専用カーネルをコンパイルした場合、ミニ Debian システムのステップをスキップできます。自分自身で確認するまでは、あなたのシステムがこの様になっていると決めつけないで下さい。

Unified Extensible Firmware Interface (UEFI) は、UEFI 仕様書の一部としてブートマネージャーを定義します。ブートマナージャーは、コンピューター電源投入時にブート設定をチェックしその設定に基づき指定された OS ブートローダーかオペレーティングシステムのカーネル(通常ブートローダー)を実行するブートプロセスの第一段階です。ブート設定は、OS ローダーや OS カーネルまでのファイルシステムパスを示す変数を含めて、NVRAM に保存された変数に定義されています。

EFI システムパーティション (ESP) は UEFI 仕様書に準拠するコンピューターで使われるデーターストレージデバイスのパーティションです。それはコンピューター電源投入時に UEFI ファームウエアーによってアクセスされ、UEFI アプリケーションやそれらのアプリケーションが実行する必要のある OS ブートローダーを含めたファイルが保存されています。(旧式の PC システム上では MBR 中に保存された BIOS がこれに代え使われているかもしれません)

ブートローダーは UEFI によって起動されるブートプロセスの2段目です。それはシステムのカーネルイメージと initrd イメージをメモリーにロードし、それらにコントロールを引き継ぎます。この initrd イメージはルートファイルシステムイメージで、そのサポートは使われるブートローダーによります。

Debian システムは普通 Linux カーネルをデフォルトのシステムカーネルとして使います。現行の 5.x Linux カーネルのための initrd イメージは技術的には initramfs (initial RAM filesystem) イメージです。

多くのブートローダと設定オプションが利用可能です。


[警告] 警告

grub-rescue-pc パッケージのイメージから作ったブート可能なレスキューメディア (CD かフロッピー) 無しにブートローダーを試してはいけません。これさえあると、ハードディスク上に機能するブートローダーが無くともシステムのブートができます。

UEFI システムの場合、GRUB2 は ESP パーティションを最初に読み、"/boot/efi/EFI/debian/grub.cfg" 中の search.fs_uuid に指定された UUID を使って GRUB2 メニュー設定ファイル "/boot/grub/grub.cfg" があるパーティションを決めます。

GRUB2 メニュー設定ファイルの重要部分は以下です:

menuentry 'Debian GNU/Linux' ... {
        load_video
        insmod gzio
        insmod part_gpt
        insmod ext2
        search --no-floppy --fs-uuid --set=root fe3e1db5-6454-46d6-a14c-071208ebe4b1
        echo    'Loading Linux 5.10.0-6-amd64 ...'
        linux   /boot/vmlinuz-5.10.0-6-amd64 root=UUID=fe3e1db5-6454-46d6-a14c-071208ebe4b1 ro quiet
        echo    'Loading initial ramdisk ...'
        initrd  /boot/initrd.img-5.10.0-6-amd64
}

/boot/grub/grub.cfg のこの部分に関して、このメニューエントリーは以下の意味があります。


[ヒント] ヒント

"/boot/grub/grub.cfg" 中の quiet を除くことでカーネルブートログを見えるようにできます。恒久的変更をするには、"/etc/default/grub" 中の "GRUB_CMDLINE_LINUX_DEFAULT="quiet"" 行を編集して下さい。

[ヒント] ヒント

"/etc/default/grub" 中の GRUB_BACKGROUND 変数をイメージファイル指すように設定するか、 "/boot/grub/" 中にイメージファイル自体を置くことで、GRUB のスプラシュイメージをカスタマイズできます。

"info grub" と grub-install(8) を参照下さい。

ミニ Debian システムはブートローダーによって起動されるブートプロセスの3段目です。メモリー上でルートファイルシステムとともにシステムカーネルを実行します。これはオプションのブートプロセスの準備段階です。

[注記] 注記

"ミニ Debian システム" は著者がこの3段目のブートプロセスを本文書中で記述するために作った言葉です。このシステムは一般に initrd とか initramfs システムと呼ばれています。類似のメモリー上のシステムは Debian インストーラーでも使われています。

"/init" スクリプトはこのメモリー上のルートファイルシステムで最初に実行されるプログラムです。それはユーザー空間でカーネルを初期化しコントロールを次の段階に引き継ぐプログラムです。このミニ Debian システムは、メインのブートプロセスが始まる前にカーネルモジュールを追加したり、ルートファイルシステムを暗号化されたファイルシステムとしてマウントする等のブートプロセスの柔軟性を提供します。

  • initramfs-tools で initramfs が作成された場合には "/init" プログラムはシェルプログラムです。

    • "break=init" 等をカーネルブートパラメーターとして与えると、本部分のブートプロセスに割り込み root シェルを獲得できます。この他の割り込み条件は "/init" スクリプトを参照下さい。このシェル環境はあなたの機器のハードウエアーを詳細に検査できるだけ十分洗練されています。

    • このミニ Debian システムで利用可能なコマンドは機能を削ったコマンドで、主に busybox(1) という GNU ツールで提供されます。

  • dracut で initramfs が作成された場合には "/init" プログラムはバイナリーの systemd プログラムです。

    • このミニ Debian システムで利用可能なコマンドは機能を削った systemd(1) 環境です。

[注意] 注意

読出しのみのルートファイルシステム上では、mount コマンドには "-n" オプションを使う必要があります。

普通の Debian システムはミニ Debian システムによって起動されるブートプロセスの4段目です。ミニ Debian システムのシステムカーネルはこの環境ででも実行され続けます。ルートファイルシステムはメモリー上から本当にハードディスク上にあるファイルシステムに切り替えられます。

多くのプログラムを起動する主ブートプロセスを行う init プログラムは、PID=1 で最初のプログラムとして実行されます。init プログラムのデフォールトのファイルパスは "/usr/sbin/init" ですが、"init=/path/to/init_program" のようなカーネルブートパラメーターにより変更できます。

Debian 8 jessie (2015年リリース) 以降では "/usr/sbin/init" は "/lib/systemd/systemd" にシムリンクされています。

[ヒント] ヒント

あなたのシステム上の実際の init コマンドは "ps --pid 1 -f" コマンドで確認できます。


[ヒント] ヒント

ブートプロセスを高速化する最新のティップは Debian wiki: BootProcessSpeedup を参照下さい。

Debian システムが起動する時、/usr/lib/systemd にシムリンクされた /usr/sbin/init が、root (UID=0) が所有する init システムプロセス (PID=1) で起動されます。systemd(1) を参照下さい。

systemd の init プロセスは、SysV 的な手続き定義スタイルではなく宣言定義スタイルで書かれた unit 設定ファイル(systemd.unit(5) 参照)に従い並列で複数プロセスを起動します。(systemd-system.conf(5) 参照):

生成されたプロセスは、それらが所属するプライベート systemd ヒエラルキー中の所属する unit にちなんで名付けられた個別の Linux コントロール グループ中に置かれます(cgroups「Linux のセキュリティ機能」 を参照下さい。)

systemd.unit(5) 中に記載された "System Unit Search Path (システムユニット探索パス)" からシステムモード用の unit がロードされます。主要なパスは優先順位順に以下です:

  • "/etc/systemd/system/*": 管理者が作成したシステム unit

  • "/run/systemd/system/*": 実行時の unit

  • "/lib/systemd/system/*": ディストリビューション パッケージ マネージャーがインストールしたシステム unit

相互依存関係は "Wants="、"Requires="、"Before="、"After="、 … ("MAPPING OF UNIT PROPERTIES TO THEIR INVERSES" in systemd.unit(5) 参照) 等の指示定義によって規定される。リソースのコントロールは (systemd.resource-control(5) 参照)によっても定義されます。

unit 設定ファイルのサッフィックスにそのタイプを以下のように折込みます:

  • *.servicesystemd がコントロールしたりスーパーバイズするプロセスを記述します。systemd.service(5) 参照下さい。

  • *.devicesysfs(5) 中に udev(7) デバイスツリーとして暴露されるデバイスを記述します。See systemd.device(5) を参照下さい。

  • *.mountsystemd がコントロールしたりスーパーバイズするファイルシステムのマウントポイントを 記述します。systemd.mount(5) を参照下さい。

  • *.automountsystemd がコントロールしたりスーパーバイズするファイルシステムの自動マウントポイントを 記述します。systemd.automount(5) を参照下さい。

  • *.swapsystemd がコントロールやスーパーバイズするスワップデバイスやファイルを 記述します。systemd.swap(5) を参照下さい。

  • *.pathsystemd がパス基準でアクティベーションするために監視するパスを 記述します。systemd.path(5) を参照下さい。

  • *.socketsystemd がソケット基準でアクティベーションするためにコントロールしたりスーパーバイズするソケットを 記述します。systemd.socket(5) を参照下さい。

  • *.timersystemd がタイマー基準でアクティベーションするためにコントロールしたりスーパーバイズするタイマーを 記述します。systemd.timer(5) を参照下さい。

  • *.slicecgroups(7) でリソースを管理します。systemd.slice(5) を参照下さい。

  • *.scope はシステムプロセスの集合を systemd のバスインターフェースを用いて管理するためにプログラムで作られます。systemd.scope(5) を参照下さい。

  • *.target は他の unit設定ファイルを組み合わせて始動時同期点を作ります。systemd.target(5) を参照下さい。

システムの始動 (init) されると systemd プロセスは (普通 "graphical.target" にシムリンクされている) "/lib/systemd/system/default.target を起動しようとします。. 最初に、"local-fs.target" や "swap.target" や "cryptsetup.target" 等のいくつかの特殊ターゲット unit (systemd.special(7) 参照) が引き込まれファイルシステムをマウントします。そして、他のターゲット unit が、ターゲット unit の依存関係で引き込まれます。詳細に関しては bootup(7) を読んで下さい。

systemd はバックワードコンパティビリティー機能を提供します。"/etc/init.d/rc[0123456S].d/[KS]name" 中の、SysV-スタイルのブートスクリプトは依然として読み込まれ処理されますし、telinit(8) は systemd の unit のアクティベーション要求に変換されます。

[注意] 注意

擬似実装された runlevel の 2 から 4 は、すべて同じ "multi-user.target" にシムリンクされます。

gdm3(8)、sshd(8)、等々経由で Debian システムにユーザーがログインする際に、当該ユーザーが所有するユーザーサービス マネージャー プロセスとして /lib/systemd/system --user が起動されます。systemd(1) を参照下さい。

systemd の ユーザーサービス マネージャーは、宣言定義スタイルで書かれた unit 設定ファイル(systemd.unit(5) 参照)に従い並列で複数プロセスを起動します。(systemd.unit(5) や [email protected](5) 参照):

systemd.unit(5) 中に記載された "User Unit Search Path (ユーザーユニット探索パス)" からユーザーモード用の unit がロードされます。主要なパスは優先順位順に以下です:

  • "~/.config/systemd/user/*": ユーザー設定 unit

  • "/etc/systemd/user/*": 管理者が作成したユーザー units

  • "/run/systemd/user/*": 実行時 unit

  • "/lib/systemd/user/*": ディストリビューション パッケージ マネージャーがインストールしたユーザー unit

これらは、「Systemd init」と同様の手法で管理されます。

コンソールに表示されるカーネルのエラーメッセージは、その閾値て設定できる。

# dmesg -n3

systemd の下では、カーネルとシステムの両方のメッセージがジャーナルサービス systemd-journald.service (所謂 journald) で、"/var/log/journal" の下の恒久的なバイナリーデーターか "/run/log/journal/" 下の非恒久的なバイナリーデーターとして記録されます。このようなバイナリー記録データーには journalctl(1) コマンドを用いてアクセスできます。例えば以下のようにして最後のブートからのログを表示できます:

$ journalctl -b

systemd のもとでは、システムログユーティリティー rsyslogd(8) はアンインストールしても大丈夫です。もしそれがインストールされている場合には、それは(systemd以前のデフォルトの "/dev/log" に代え)揮発性のバイナリーログデーターを読むように挙動を変え、伝統的で恒久的な ASCII システムログデーターを作成します。これは、"/etc/default/rsyslog" や "/etc/rsyslog.conf" を用いてログファイルと画面表示の両方に関してカスタマイズ可能です。rsyslogd(8) や rsyslog.conf(5) を参照下さい。また、「ログアナライザー」も参照下さい。

systemd は init システムを提供するのみならず、systemctl(1) コマンドで汎用システム管理機能を提供します。

表3.6 典型的な systemctl コマンド断片の例

操作 コマンド断片
全使用可能なユニットタイプをリスト "systemctl list-units --type=help"
メモリー中の全 ターゲット unit のリスト "systemctl list-units --type=target"
メモリー中の全 サービス unit のリスト "systemctl list-units --type=service"
メモリー中の全 デバイス unit のリスト "systemctl list-units --type=device"
メモリー中の全 マウント unit のリスト "systemctl list-units --type=mount"
メモリー中の全ソケット unit のリスト "systemctl list-sockets"
メモリー中の全タイマー unit のリスト "systemctl list-timers"
"$unit" 始動 "systemctl start $unit"
"$unit" 停止 "systemctl stop $unit"
サービス特定の設定の再ロード "systemctl reload $unit"
"$unit" 停止と始動 "systemctl restart $unit"
"$unit" 始動と、他全ての停止 "systemctl isolate $unit"
"graphical" に切り替え(GUI システム) "systemctl isolate graphical"
"multi-user" に切り替え(CLI システム) "systemctl isolate multi-user"
"rescue" に切り替え(シングルユーザー CLI システム) "systemctl isolate rescue"
"$unit" に kill 信号を送る "systemctl kill $unit"
"$unit" サービスがアクティブかを確認 "systemctl is-active $unit"
"$unit" サービスが失敗かを確認 "systemctl is-failed $unit"
"$unit|$PID|device" の状態を確認 "systemctl status $unit|$PID|$device"
"$unit|$job" の属性を表示 "systemctl show $unit|$job"
失敗した "$unit" をリセット "systemctl reset-failed $unit"
全ての unit サービスの依存関係をリスト "systemctl list-dependencies --all"
システムにインストールされた unit ファイルをリスト "systemctl list-unit-files"
"$unit" を有効にする(symlink 追加) "systemctl enable $unit"
"$unit" を無効にする(symlink 削除) "systemctl disable $unit"
"$unit" のマスクを外す("/dev/null" へのsymlink を削除) "systemctl unmask $unit"
"$unit" にマスクをかける("/dev/null" へのsymlink を追加) "systemctl mask $unit"
デフォールトのターゲット設定を取得 "systemctl get-default"
"graphical" にデフォールトのターゲットを設定 (GUI システム) "systemctl set-default graphical"
"multi-user" にデフォールトのターゲットを設定 (CLI システム) "systemctl set-default multi-user"
ジョブ環境の表示 "systemctl show-environment"
ジョブ環境 "variable"(変数)を "value(値)に設定する" "systemctl set-environment variable=value"
ジョブ環境 "variable" (変数)の設定を解除する "systemctl unset-environment variable"
全 unit ファイルとデーモンをリロード "systemctl daemon-reload"
システムをシャットダウンする "systemctl poweroff"
システムのシャットダウンとリブート "systemctl reboot"
システムのサスペンド "systemctl suspend"
システムのハイバーネート "systemctl hibernate"

ここで、上記の例の中の "$unit" は単一の unit 名 (.service.target といったサフィックスは任意) とか、多くの場合、現在メモリー中の全 unit の主名称に対して fnmatch(3) を用いて"*" や "?" や "[]" 等のシェルスタイルのグロブによる複数 unit 指定であっても良い。

上記例中のシステムの状態を変えるコマンドは必要な管理特権を獲得させるべく "sudo" を典型的には前置されています。

"systemctl status $unit|$PID|$device" の出力は色付きドット ("●") を使い unit の状態が一目瞭然としています。

  • 白い "●" は "活動停止" や "活動停止中" の状態を示します。

  • 赤い "●" は "失敗発生" や "エラー発生" の状態を示します。

  • 緑の "●" は "活動中" や "リローディング" や "活動化中" の状態を示します。

以下は、systemd の下での他のモニタリングコマンドです。cgroups(7) を含めた該当のマンページを読んで下さい。


普通のディスクやネットワークのファイルシテムのマウントオプションは "/etc/fstab" で設定されます。fstab(5) と 「マウントオプションによるファイルシステムの最適化」を参照下さい。

暗号化されたファイルシステムの設定は "/etc/crypttab" で設定されます。crypttab(5) を参照下さい。

mdadm(8) を用いるソフトウェアー RAID は "/etc/mdadm/mdadm.conf" で設定されます。mdadm.conf(5) を参照下さい。

[警告] 警告

各ブートアップごとに、全てのファイルシステムをマウントした後で、"/tmp" と "/var/lock" と "/var/run" 中の一時ファイルはクリーンされます。

クラウドシステムインスタンス "Debian オフィッシャルクラウドイメージ" とか類似のイメージのクローンとしてローンチされるかもしれません。そのようなシステムインスタンスの場合、ホスト名やファイルシステムやネットワーキングやロケールや SSH キーやユーザーとかグループとかは cloud-initnetplan.io パッケージが提供する機能を使って、オリジナルのシステムイメージ中に置かれたファイルとかそのローンチ時に供給される外部データー等の複数のデーターソースを用いて設定されます。これらのパッケージは YAML データーを使った宣言的なシステム設定を可能にします。

詳しくは "Debian とその系統でのクラウドコンピューティング""Cloud-init ドキュメンテーション"「クラウドのための現代的なネットワーク設定」を参照下さい。

デフォルトのインストールでは、多くのネットワークサービス(6章ネットワークアプリケーション を参照) はブート時に systemd によってブート時に network.target の後に起動される。"sshd" も例外ではありません。カスタム化の例としてオンデマンド起動に "sshd" をかえましょう。

最初に、システムがインストールしたサービスの unit を無効化しましょう。

 $ sudo systemctl stop sshd.service
 $ sudo systemctl mask sshd.service

古典的 Unix サービスでは indetd (または xinetd) スーパーサーバーによりオンデマンドでソケットをアクティベーションしました。systemd では、*.socket*.service unit 設定ファイルを追加することでこれと同等のことが できます。

聞くソケットを指定するには sshd.socket

[Unit]
Description=SSH Socket for Per-Connection Servers

[Socket]
ListenStream=22
Accept=yes

[Install]
WantedBy=sockets.target

sshd.socket に対応するサービスファイルの [email protected]

[Unit]
Description=SSH Per-Connection Server

[Service]
ExecStart=-/usr/sbin/sshd -i
StandardInput=socket

そして、再ロードします。

 $ sudo systemctl daemon-reload

udev システムはハードウエアーの自動検出と初期化のメカニズムを提供します (udev(7) 参照下さい)。カーネルが各デバイスを発見すると、udev システムは sysfs ファイルシステム (「procfs と sysfs」を参照下さい) からの情報を使いユーザープロセスを起動し、modprobe(8) プログラム (「カーネルモジュール初期化」を参照下さい) を使ってそれをサポートする必要なカーネルモジュールをロードし、対応するデバイスノードを作成します。

[ヒント] ヒント

もし "/lib/modules/kernel-version/modules.dep" が何らかの理由で depmod(8) によって適正に生成されていなかった場合には、モジュールは udev システムによる期待にそってロードされないかもしれません。これを修正するには、"depmod -a" を実行します。

"/etc/fstab" 中のマウントルールでは、デバイス名が静的なデバイス名である必要がありません。"/dev/sda" 等のデバイス名ではなく UUID を使ってデバイスをマウントできます。「UUID を使ってパーティションをアクセス」を参照下さい。

udev システムは少々動くターゲットなので、詳細は他のドキュメントに譲り、ここでは最小限の記述に止めます。

[警告] 警告

udev(7) で語られているように udev ルール中の RUN でバックアップスクリプトのような長時間実行されるプログラムを実行しようとしないで下さい。そうする代わりには、適切な systemd.service(5) ファイルを作成しそれを有効化しましょう。「マウントイベントがトリガーするバックアップ」 を参照下さい。

modprobe(8) プログラムは、ユーザープロセスからカーネルモジュールを追加や削除することで実行中の Linux カーネルの設定を可能にします。udev システム (「udev システム」を参照下さい) は、その起動を自動化しカーネルモジュールの初期化を補助します。

"/etc/modules" ファイル中にリストしてプリロードする必要のある (modules(5) 参照下さい) 次に記すような非ハードウエアーや特殊ハードウエアーのドライバーモジュールがあります。

modprobe(8) プログラムのための設定ファイルは、modprobe.conf(5) で説明されているように "/etc/modprobes.d/" ディレクトリーの下にあります。(あるカーネルモジュールが自動ロードされるのを避けるには、"/etc/modprobes.d/blacklist" ファイル中にブラックリストします。)

depmod(8) プログラムによって生成される "/lib/modules/version/modules.dep" ファイルは、modprobe(8) プログラムによって使われるモジュール依存関係を記述します。

[注記] 注記

ブート時に modprobe(8) を使ってのモジュールロードの問題に出会った場合には、"depmod -a" として "modules.dep" を再構築をするとこの様な問題が解消できるかもしれません。

modinfo(8) プログラムは Linux カーネルモジュールに関する情報を表示します。

lsmod(8) プログラムは "/proc/modules" の内容を読みやすい形式にして、どのカーネルモジュールが現在ロードされているかを表示します。

[ヒント] ヒント

あなたのシステム上の正確なハードウエアーを特定します。「ハードウエアーの識別」を参照下さい。

ブート時に期待されるハードウエアー機能をアクティベートするように設定もできます。「ハードウエアー設定」を参照下さい。

あなたのデバイスのサポートは、カーネルを再コンパイルすれば追加できます。「カーネル」を参照下さい。