Product SiteDocumentation Site

第 9 章 Unix サービス

9.1. システム起動
9.1.1. systemd init システム
9.1.2. The System V init system
9.2. リモートログイン
9.2.1. 安全なリモートログイン、SSH
9.2.2. リモートグラフィカルデスクトップの利用
9.3. 権限の管理
9.4. 管理インターフェース
9.4.1. ウェブインターフェースを使った管理、webmin
9.4.2. パッケージの設定、debconf
9.5. syslog システムイベント
9.5.1. 原理とメカニズム
9.5.2. 設定ファイル
9.6. inetd スーパーサーバ
9.7. cronatd を使ったスケジューリングタスク
9.7.1. crontab ファイルの書式
9.7.2. at コマンドの利用
9.8. 非同期タスクのスケジューリング、anacron
9.9. クォータ
9.10. バックアップ
9.10.1. rsync を使ったバックアップ
9.10.2. バックアップなしのマシンの復元
9.11. ホットプラグ機能、hotplug
9.11.1. 前書き
9.11.2. 命名問題
9.11.3. udev の動作原理
9.11.4. 具体例
9.12. 電源管理、Advanced Configuration and Power Interface (ACPI)
この章では、多くの Unix システムに共通する数多くの基本的なサービスをカバーします。すべての管理者はこれらの基本的なサービスに精通しているべきです。

9.1. システム起動

コンピュータを起動する際、コンソール画面にスクロールされる多くのメッセージには、実行されている多くの自動初期化と自動設定に関する情報が表示されます。この段階の挙動を少し変えたいと思うことがあるかもしれません。これは起動処理をよく理解する必要があることを意味しています。この節の目的は起動処理をよく理解することにあります。
最初に BIOS がコンピュータを制御し、ディスクを検出し、マスターブートレコードを読み込み、ブートローダを実行します。以降、ブートローダが引き継ぎ、ディスクからカーネルを見つけ、カーネルを読み込んで実行します。そして、カーネルが初期化され、ルートファイルシステムを含むパーティションの検索とマウントを開始し、最後に最初のプログラムである init を実行します。「ルートパーティション」と init は RAM の中にだけ存在する仮想ファイルシステム (これは現在「initramfs」と呼ばれていますが、以前は「初期化 RAM ディスク」という意味で「initrd」と呼ばれていました) 上に置かれていることが多いです。多くの場合、initramfs はハードドライブのファイルかネットワークから、ブートローダによってメモリに読み込まれます。initramfs には、カーネルが「真の」ルートファイルシステムを読み込むために必要な最低限の要素が含まれています。具体的に言えば、ハードドライブやそれなしではシステムが起動できないその他のデバイスのドライバモジュール、より頻繁にあるのが、RAID アレイを組み立て、暗号化されたパーティションを開き、LVM ボリュームを有効化するなどの初期化スクリプトとモジュールが含まれています。一度ルートパーティションがマウントされたら、initramfs は制御を真の init に渡し、マシンは標準的な起動処理に戻ります。
systemd を使う Linux の動くコンピュータの起動シーケンス

図 9.1 systemd を使う Linux の動くコンピュータの起動シーケンス

9.1.1. systemd init システム

「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.targetsound.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 を使います。そして他のサブコマンドには reloadrestart があります。
サービスを有効化するには (たとえば、起動時に自動的にサービスを開始するには)、systemctl enable servicename.service (または disable) を使います。is-enabled を使えば、サービスの状態を確認することが可能です。
systemd の興味深い機能として、journald と名付けられたログ記録部品が挙げられます。journaldsyslogd などのより伝統的なログ記録ファイルシステムを補完するために誕生しましたが、サービスとサービスが生成したメッセージ間を正しく結び付けたり、初期化シーケンスが生成するエラーメッセージを保存する能力などの興味深い機能を追加しています。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.
これらのスクリプトは特に以下の点を担当します。
  • コンソールキーボードの設定。
  • ドライバの読み込み。ほとんどのカーネルモジュールは、ハードウェアを検出した時にカーネル自身によって読み込まれます。さらに追加のドライバは、それに対応するモジュールが /etc/modules にリストされている場合に、読み込まれます。
  • ファイルシステムの整合性確認。
  • ローカルパーティションのマウント。
  • ネットワークの設定。
  • ネットワークファイルシステム (NFS) のマウント。
この段階の後、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 ディレクトリにスクリプトを追加したりおよび削除したりすることで) 特定の要求に順応させることが可能です。
Boot sequence of a computer running Linux with System V init

図 9.2 Boot sequence of a computer running Linux with System V init

さまざまな /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 を実行します。