コンピュータを起動する際、コンソール画面にスクロールされる多くのメッセージには、実行されている多くの自動初期化と自動設定に関する情報が表示されます。この段階の挙動を少し変えたいと思うことがあるかもしれません。これは起動処理をよく理解する必要があることを意味しています。この節の目的は起動処理をよく理解することにあります。
「init の実体」は現在 systemd によって提供されています。この節ではこの init システムに関して説明します。
Systemd はシステムの設定を担当している複数のプロセスを実行します。具体的に言えば、キーボード、ドライバ、ファイルシステム、ネットワーク、サービスが設定されます。Systemd はシステム全体におよぶ包括的視点と各要素の要求条件を満足させながらこれを行います。各要素は「ユニットファイル」(これだけでは済まない場合もあります) によって定義されています。さらにユニットファイルの一般的な構文は広く使われている「*.ini ファイル」の構文から派生したもので、[section]
ヘッダでグループ化された key = value
ペアを使います。ユニットファイルは /lib/systemd/system/
と /etc/systemd/system/
の下に保存されます。さらにユニットファイルはいくつかの形式がありますが、われわれは「service」型と「target」型に注目します。
systemd の「service ファイル」は systemd が管理するプロセスを記述します。「service ファイル」には大ざっぱに言って古いスタイルの init スクリプトと同じ情報が含まれていますが、宣言的な方法 (そしてより簡潔な方法) を使ってその情報が記述されています。systemd は繰り返しタスク (プロセスの開始と停止、状態確認、ログ記録、特権の取り消し、など) の大部分を取り扱い、service ファイルにはプロセスに特有の情報を記入する必要があります。たとえば以下は SSH 用の service ファイルです。
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=sshd.service
ご覧の通り、コードはとても少なく、宣言だけから成っています。systemd は作業進行状況を表示したり、プロセスを監視したり、必要な時にプロセスを再起動することを担当します。
systemd の「target ファイル」はシステムの状態を表現するもので、このファイルを使って利用できる状態にされていなければならないサービス群を指定します。「target ファイル」は昔ながらのランレベルに相当するものとして考えることが可能です。target ファイルの 1 つに local-fs.target
があります。さらにこのターゲットを処理する際には、残りのシステムはすべてのローカルファイルシステムがマウントされアクセスできるようになっている状態を仮定することが可能です。また別の target ファイルに network-online.target
と sound.target
があります。ターゲットの依存関係を指定するには target ファイルの (Requires=
行で) リスト指定するか、/lib/systemd/system/targetname.target.wants/
ディレクトリに service ファイルへのシンボリックリンクを保存することで行います。たとえば、/etc/systemd/system/printer.target.wants/
には /lib/systemd/system/cups.service
へのリンクが含まれます。そしてこのため systemd は printer.target
を処理する前に CUPS が実行されていることを保証するでしょう。
ユニットファイルは宣言型の設定ファイルでありスクリプトやプログラムではないため、直接実行することは不可能で、systemd によってのみ解釈されます。いくつかのユーティリティを使うことで、管理者は systemd と情報をやり取りして、システムおよびシステム部品の状態を制御することが可能です。
systemd と情報をやり取りする 1 番目のユーティリティとして systemctl
が挙げられます。systemctl
を引数なしで実行した場合、systemd が把握しているすべてのユニットファイル (無効化されているものを除く) およびその状態が表示されます。systemctl status
を使うことで、サービスおよび関連するプロセスをよりわかりやすく表示することが可能です。サービスの名前を指定した (systemctl status ntp.service
のように指定した) 場合、systemctl
はさらに詳しい情報および指定したサービスに関連するログの最後の (最新の) 数行を表示します。
手作業でサービスを開始するのは簡単で、systemctl start servicename.service
を実行するだけです。予想通り、サービスを停止するには systemctl stop servicename.service
を使います。そして他のサブコマンドには reload
と restart
があります。
サービスを有効化するには (たとえば、起動時に自動的にサービスを開始するには)、systemctl enable servicename.service
(または disable
) を使います。is-enabled
を使えば、サービスの状態を確認することが可能です。
systemd の興味深い機能として、journald
と名付けられたログ記録部品が挙げられます。journald
は syslogd
などのより伝統的なログ記録ファイルシステムを補完するために誕生しましたが、サービスとサービスが生成したメッセージ間を正しく結び付けたり、初期化シーケンスが生成するエラーメッセージを保存する能力などの興味深い機能を追加しています。journalctl
コマンドの助けを借りれば、メッセージを後から表示することも可能です。引数なしで実行した場合、journalctl
は起動後に発生したすべてのログメッセージを表示しますが、引数を与えずに実行することはほとんどないでしょう。ほとんどの場合、サービス識別子を与えて journalctl
を実行することが多いでしょう。
#
journalctl -u ssh.service
-- Logs begin at 火 2015-03-31 17:08:49 JST, end at 水 2015-04-01 00:06:02 JST. --
3月 31 17:08:55 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
3月 31 17:08:55 mirtuel sshd[430]: Server listening on :: port 22.
3月 31 17:09:00 mirtuel sshd[430]: Received SIGHUP; restarting.
3月 31 17:09:00 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
3月 31 17:09:00 mirtuel sshd[430]: Server listening on :: port 22.
3月 31 17:09:32 mirtuel sshd[1151]: Accepted password for roland from 192.168.1.129 port 53394 ssh2
3月 31 17:09:32 mirtuel sshd[1151]: pam_unix(sshd:session): session opened for user roland by (uid=0)
また他の役に立つコマンドラインフラグとして -f
が挙げられます。これを使った場合、journalctl
は新しいメッセージを受け取ったらそのメッセージを表示し続けます (もっと言えば tail -f file
のやり方です)。
サービスが期待通りに動いていないように見える場合、問題解決に向けて手始めに systemctl status
を実行し、今現在サービスが動いているか否かを確認します。そしてサービスが実行されていなくて、systemctl status
の表示したメッセージが問題の原因を解明するのに十分でない場合、journald が収集したサービスに関連するログを確認します。たとえば、SSH サービスが動いていないと仮定します。
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: failed (Result: start-limit) since 水 2015-04-01 00:30:36 JST; 1s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Process: 1188 ExecStart=/usr/sbin/sshd -D $SSHD_OPTS (code=exited, status=255)
Main PID: 1188 (code=exited, status=255)
4月 1 00:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
4月 1 00:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
4月 1 00:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
4月 1 00:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
4月 1 00:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
journalctl -u ssh.service
-- Logs begin at 水 2015-04-01 00:29:27 JST, end at 水 2015-04-01 00:30:36 JST. --
4月 1 00:29:27 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
4月 1 00:29:27 mirtuel sshd[424]: Server listening on :: port 22.
4月 1 00:29:29 mirtuel sshd[424]: Received SIGHUP; restarting.
4月 1 00:29:29 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
4月 1 00:29:29 mirtuel sshd[424]: Server listening on :: port 22.
4月 1 00:30:10 mirtuel sshd[1147]: Accepted password for roland from 192.168.1.129 port 38742 ssh2
4月 1 00:30:10 mirtuel sshd[1147]: pam_unix(sshd:session): session opened for user roland by (uid=0)
4月 1 00:30:35 mirtuel sshd[1180]: /etc/ssh/sshd_config line 28: unsupported option "yess".
4月 1 00:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
4月 1 00:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
4月 1 00:30:35 mirtuel sshd[1182]: /etc/ssh/sshd_config line 28: unsupported option "yess".
4月 1 00:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
4月 1 00:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
4月 1 00:30:35 mirtuel sshd[1184]: /etc/ssh/sshd_config line 28: unsupported option "yess".
4月 1 00:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
4月 1 00:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
4月 1 00:30:36 mirtuel sshd[1186]: /etc/ssh/sshd_config line 28: unsupported option "yess".
4月 1 00:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
4月 1 00:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
4月 1 00:30:36 mirtuel sshd[1188]: /etc/ssh/sshd_config line 28: unsupported option "yess".
4月 1 00:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
4月 1 00:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
4月 1 00:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
4月 1 00:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
4月 1 00:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
vi /etc/ssh/sshd_config
#
systemctl start ssh.service
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since 水 2015-04-01 00:31:09 JST; 2s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 1222 (sshd)
CGroup: /system.slice/ssh.service
└─1222 /usr/sbin/sshd -D
#
ここでは SSH サービスの状態が失敗状態であることを確認した後、ログの確認作業に進みました。その結果、ログは設定ファイル内にエラーがあることを示しています。そこで設定ファイルを編集してエラーを修正した後、SSH サービスを再起動し、SSH サービスが本当に動いていることを確認しています。
9.1.2. The System V init system
The System V init system (which we'll call init for brevity) executes several processes, following instructions from the
/etc/inittab
file. The first program that is executed (which corresponds to the
sysinit step) is
/etc/init.d/rcS
, a script that executes all of the programs in the
/etc/rcS.d/
directory.
これらのスクリプトは特に以下の点を担当します。
この段階の後、init
が引き継ぎ、デフォルトランレベル (通常ランレベル 2) で有効化されたプログラムを起動します。init
は /etc/init.d/rc 2
を実行します。これは /etc/rc2.d/
に置かれて、「S」で始まる名前のすべてのサービスを開始するコマンドです。「S」の後に続く 2 桁の数字は、歴史的に言って、起動するサービスの順番を定義するために使われていました。しかし今やデフォルトの起動システムは insserv
を使って、スクリプト同士の依存関係に従った起動順を自動的に決定します。このため、各起動スクリプトはサービスを起動または終了させる時に満足しなければいけない条件を宣言します (たとえば、あるサービスは他のサービスの前または後に起動しなければいけないなどの条件を宣言します)。そして、init
は条件を満足するようにサービスを起動します。このため、スクリプトの静的な番号付けはもはや考慮されません (しかしスクリプトの名前は必ず「S」で始まり、その後ろに 2 桁の番号を付け、依存関係に使われる実際のスクリプトの名前を続けなければいけません)。一般に、ベースシステム (ログ記録を担当している rsyslog
やポート割り当てを担当している portmap
) が最初に起動され、その後に標準的なサービスとグラフィカルインターフェース (gdm3
) が起動されます。
この依存関係に基づく起動システムのおかげで、自動的な起動順の再定義が可能になります。これは手作業でやるにはちょっと退屈な作業で、人的ミスの危険性があります。なぜなら、起動順は宣言された依存関係に従って定義されるからです。別の利益として、他のサービスに依存しないサービスは並列して開始できるという点があります。このことにより、起動処理を加速できます。
init
はいくつかのランレベルを区別します。そうすることで、telinit new-level
コマンドを使ってあるランレベルから別のランレベルに切り替えることができます。即座に init
は新しいランレベルで /etc/init.d/rc
を再実行します。このスクリプトは欠けているサービスを開始し、既に不要となったサービスを停止します。これを行うために、init
は /etc/rcX.d
の内容を参照します (ここで X は新しいランレベルです)。(「Start」の)「S」で始まるスクリプトは開始されるサービスです。そして (「Kill」の)「K」で始まるスクリプトは停止されるサービスです。このスクリプトは前のランレベルで既に起動されているサービスは開始しません。
By default, System V init in Debian uses four different runlevels:
レベル 0 はコンピュータの電源を切る際に一時的に使われるだけです。このため「K」スクリプトしか含まれません。
シングルユーザモードとしても知られるレベル 1 はシステムの機能抑制モードに相当します。さらに、このモードでは基本的なサービスだけが提供され、このモードは一般ユーザがマシンを利用していないメンテナンスの際に使われることを意図しています
レベル 2 は通常動作用のモードで、ネットワークサービス、グラフィカルインターフェース、ユーザログインなどの機能を使うことが可能です。
レベル 6 はレベル 0 と似ていますが、再起動前のシャットダウン段階中に使われる点が異なります。
他のレベル、特に 3 から 5 まで、も存在します。デフォルトでこれらのランレベルはレベル 2 と同様に動作しますが、管理者はこれを変えて (ランレベルに対応する /etc/rcX.d
ディレクトリにスクリプトを追加したりおよび削除したりすることで) 特定の要求に順応させることが可能です。
さまざまな /etc/rcX.d
ディレクトリに含まれるすべてのスクリプトは /etc/init.d/
に格納されたスクリプトの実体を指すシンボリックリンク — パッケージのインストール時に update-rc.d
プログラムによって作られます — に過ぎません。管理者は、調整したパラメータを与えて update-rc.d
を再実行して、各ランレベルで利用できるサービスを微調整することが可能です。update-rc.d
の構文は update-rc.d(1) マニュアルページに詳しく説明されています。サービスを無効化する目的で、(remove
パラメータを付けて) すべてのシンボリックリンクを削除するのは悪い方法であるという点に注意してください。その代わりに、単純に希望するランレベルでそのサービスを起動しないよう設定するべきです (一方で、万が一、前のランレベルでそのサービスが実行されている場合に備えて、そのランレベルでもサービスを停止するために必要なシンボリックリンクを確保しておくべきです)。update-rc.d
は複雑なインターフェースを持っているため、(rcconf パッケージの提供する) rcconf
を使いたいと思うかもしれません。rcconf
はよりユーザにとって使い勝手の良いインターフェースを提供します。
最後に、init
はさまざまな仮想コンソール用の制御プログラム (getty
) を開始します。この制御プログラムがプロンプトを表示し、ユーザ名の入力を待ち、セッションを開始するために login user
を実行します。