Product SiteDocumentation Site

第 9 章 Unix サービス

9.1. システム起動
9.1.1. systemd init システム
9.1.2. System V init システム
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 があります。local-fs.target で定義された状態に到達した場合、残りのシステムはすべてのローカルファイルシステムがマウントされアクセスできるようになっている状態を仮定することが可能です。また別の target ファイルに network-online.targetsound.target があります。ある target ファイルの依存関係は対象の target ファイルの中 (Requires= 行) に依存関係にある service ファイルを記述するか、対象の /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. System V init システム

System V init システム (これを短縮して init と呼びます) は /etc/inittab ファイルの指示に従って複数のプロセスを実行します。実行される最初のプログラム (sysinit 段階に相当します) は /etc/init.d/rcS で、これは /etc/rcS.d/ ディレクトリに含まれるすべてのプログラムを起動するスクリプトです。
/etc/rcS.d/ ディレクトリに含まれるスクリプトは特に以下の点を担当します。
  • コンソールキーボードの設定。
  • ドライバの読み込み。ほとんどのカーネルモジュールはハードウェアを検出した時にカーネル自身によって読み込まれます。追加のドライバはそれに対応するモジュールが /etc/modules にリストされている場合に読み込まれます。
  • ファイルシステムの整合性確認。
  • ローカルパーティションのマウント。
  • ネットワークの設定。
  • ネットワークファイルシステム (NFS) のマウント。
/etc/init.d/rcS の完了後、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 を再実行します。/etc/init.d/rc は欠けているサービスを開始し、既に不要となったサービスを停止します。これを行うために、/etc/init.d/rc/etc/rcX.d ディレクトリの内容を参照します (ここで X は新しいランレベルです)。このディレクトリに含まれる (「Start」の)「S」で始まるスクリプトは開始されるサービスで、(「Kill」の)「K」で始まるスクリプトは停止されるサービスです。/etc/init.d/rc は切り替え前のランレベルで既に起動されているサービスは開始しません。
デフォルトで、Debian の System V init は 4 種類のランレベルを使います。
  • レベル 0。これはコンピュータの電源を切る際に一時的に使われるだけです。このため「K」スクリプトしか含まれません。
  • レベル 1。これはシングルユーザモードとしても知られ、システムの機能抑制モードに相当します。このモードは基本的なサービスだけを提供し、一般ユーザがマシンを利用していないメンテナンスの際に使われることを意図しています
  • レベル 2。これは通常動作用のモードで、ネットワークサービス、グラフィカルインターフェース、ユーザログインなどの機能を使うことが可能です。
  • レベル 6。これはレベル 0 と似ていますが、再起動前のシャットダウン段階中に使われる点が異なります。
その他のレベル。レベル 3 からレベル 5 までも存在します。デフォルトでこれらのランレベルはレベル 2 と同様に動作しますが、管理者はこれらのレベルを特定の要求に順応させるためのレベルに書き換えることが可能です (ランレベルに対応する /etc/rcX.d ディレクトリにスクリプトを追加したりおよび削除したりする必要があります)。
System V init を使う Linux の動くコンピュータの起動シーケンス

図 9.2 System V init を使う Linux の動くコンピュータの起動シーケンス

/etc/rcX.d ディレクトリに含まれるすべてのスクリプトは /etc/init.d/ に格納されたスクリプトの実体を指すシンボリックリンクに過ぎません (シンボリックリンクはパッケージのインストール時に update-rc.d プログラムによって作られます)。各ランレベルで利用できるサービスを微調整するには、管理者が調整パラメータを与えて update-rc.d を再実行する必要があります。update-rc.d の構文は update-rc.d(1) マニュアルページに詳しく説明されています。サービスを無効化したい場合に (remove パラメータを与えて) すべてのシンボリックリンクを削除するのは悪い方法であるという点に注意してください。remove パラメータを使う代わりに、単純に希望するランレベルでそのサービスを起動しないよう disable を使って設定するべきです (同時に、万が一切り替え前のランレベルで対象のサービスが実行されている場合に備えて、切り替え後のランレベルでサービスを停止するために必要なシンボリックリンクを確保しておくべきです)。update-rc.d は複雑なインターフェースを持っているため、rcconf (rcconf パッケージに含まれます) を使いたいと思うかもしれません。rcconf はユーザにとってさらに使い勝手の良いインターフェースを提供します。
最後に、init はさまざまな仮想コンソール用の制御プログラム (getty) を開始します。getty はプロンプトを表示し、ユーザ名の入力を待ち、セッションを開始するために login user を実行します。