Linux リテラシ - 第4回 デーモン

辻本

今回はデーモンと呼ばれるものについて取り上げます。デーモンはユーザーが意識することがないような裏の部分で動いており、システムを維持したりユーザーにサービスを提供したりといったことを行っています。ちなみにこのデーモンとは悪魔の事を指すdemonではなくdaemon(守護神)です。
後期のサーバーリテラシで実際に立ち上げるWebサーバーなどもデーモンの一種です。この講義の中で取り上げるのはそういったアピール性の高い便利なサービスを提供する類のものではなく、地味ですがシステムに欠かすことのできないものです。

プロセス

デーモンはシステムの維持にあたっているといいましたが、もちろんあなたが動かしているLinux上でもデーモンは動いています。
psコマンドにauxというオプションをつけて実行することで、現在システム上に存在するすべてのプロセスを確認できます。ここで出力されるプロセスがすべてデーモンというわけではありませんが「見えないところで動いている」ということについては感じることが出来ると思います。

$ ps aux

プロセスとは今まさに実行されている(している)プログラムのことです。これはデーモンだけにとどまらず、文字通りOS上で動いているものすべてです。今まで使ってきたlsなどもプロセスとして動いています。

  1. シェルでlsと入力してEnter
  2. シェルがlsプロセスを生成
  3. 生成されたプロセスがディレクトリのリストを出力
  4. lsプロセス終了

分かりづらいですが、/bin/lsというプログラム自体はプロセスではありません。プログラムを「実行」することで初めてOS上でプロセスとして動くことになります。

各プロセスは次のような属性を持ちます。

PID(Process ID)
プロセスを識別するための値。必ずプロセス間でユニークな値となる。
ユーザー、グループ
プロセスの実行権限。ファイルのパーミッションと比較され、アクセス制御を実現する。

シグナル

ユーザーはプロセスを外部から制御するためにシグナル(signal -- 信号)を送ることができます。シグナルはその用途に応じて種類が分かれています。

種類 用途
INT(INTerrupt) プロセスを中断(終了)するために使います。端末上でCtrl+c(^C)と入力することで、フォアグラウンドのプロセスに送ることができます。
TERM(TERMinated) プロセスを終了させるために使います。
HUP(HangUP) 主にデーモンプロセスに対して設定ファイルを再読み込みさせるために使われます。
KILL(KILLed) INTやTERMでは終了できないような(暴走している)プロセスを強制的に終了させるために使われます。

シグナルはkillコマンドを使って送ります。コマンド名から受ける印象ではKILLシグナルしか送ることができないような気がするかもしれませんが、そんなことはありません。

# PID 1234のプロセスにTERMシグナルを送る
$ kill -TERM 1234

# 同上
$ kill 1234

# PID 1234のプロセスにHUPシグナルを送る
$ kill -HUP 1234

# PID 1234のプロセスにKILLシグナルを送る
$ kill -KILL 1234

デーモンの起動

デーモンはシステムのブート時にまとめて自動的に起動されます。その仕組みを知る前にまずデーモンの起動と終了の仕方について触れておきましょう。

通常デーモンを起動するときには起動スクリプトと呼ばれるシェルスクリプトが使われます。これらのファイルは/etc/init.dに置かれており、次のようにして使います。

# /etc/init.d/daemon start   (起動)
# /etc/init.d/daemon stop    (終了)

/etc/init.dの中を見てみれば分かりますが、ここにはたくさんの起動スクリプトがあります。だからといってこれらすべてが起動しているわけではありません。システム管理者はこの中からマシンの用途に合ったデーモンだけを選んで、Linux起動時に自動的に起動するようにさせることができます。それを設定するコマンドがntsysvです。

実行すると上図のようにグラフィカルな設定画面が現れます。「*」が付いているサービスが自動的に起動するものです。ntsysvの使い方は次のとおりです。

キー 機能
スペース状態の切り替え
F1 詳細の表示
タブ 項目間の移動

システムにとっていらないデーモンを起動しておくことは、限りあるマシンのリソースを無駄に消費するだけでなくセキュリティ上のリスクを抱えることにもつながります。これらを適切に取捨選択し設定することはシステム管理者が行うべき基本的な事柄の一つです。

Linuxの起動シーケンス

ntsysvは便利なツールですが、実際に何をしているか理解しておくことも大切です。それを念頭に置いた上でLinuxの起動シーケンスの中でどのようにデーモンが起動されるかを見ていきましょう。

initプロセスとランレベル

カーネルが読み込まれプロセスを生成できる環境が整うと、システムは一番最初のプロセスとしてinitプロセスというものを生成します。initプロセスは/etc/inittabに従ってシステムの初期化を行います。このファイルの中で注目して欲しいのは次の部分です。

# Default runlevel. The runlevels used by RHS are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id:5:initdefault:

これはLinuxをランレベル5で動かすという事を意味します。Linuxは起動中ある一つの動作状態を取るのですが、それをランレベルといいます。その内訳は上のコメントにもありますが、このうちよく利用する可能性のある物を抜粋しておきます。

ランレベル用途
5 GUIを利用する場合
3 CUIのみ利用する場合
1 障害復旧用

シンボリックリンク

ランレベルが分かったところでいよいよデーモンの起動に入ります、と言いたいところですがその前にもう一つだけ新しい概念を理解する必要があります。それがシンボリックリンクです。

シンボリックリンクは、他のファイルやディレクトリへのリンクとなります。リンクに対するアクションは、そのリンク先に対して行っているのと同じようになります。Windowsのショートカットに似たような物、といって分かる人がいるかもしれません。

抽象的な話をしていても分かりづらいので具体例を挙げます。

$ pwd
/home/user

$ ls -F
a  c/

$ ls -F c/
c-a

$ cat a
b

#
# /home/user/aというファイルに対して/home/user/bという名前でシンボリックリンクを作成
#
$ ln -s /home/user/a /home/user/b
$ ls -l
-rw-rw-r--  1 user user    2  5月 30 00:53 a
lrwxrwxrwx  1 user user   12  5月 30 00:54 b -> /home/user/a
drwxrwxr-x  2 user user 4096  5月 30 00:53 c

#
# aと内容が同じ
#
$ cat b
b

#
# aの内容を変更する
#
$ echo bb > a

#
# 当然bから見ても内容が変わっている
#
$ cat b
bb

#
# cというディレクトリにdという名前でシンボリックリンクを作成
#
$ ln -s c d
$ ls -l
-rw-rw-r--  1 user user    0  5月 30 01:03 a
lrwxrwxrwx  1 user user   12  5月 30 00:54 b -> /home/user/a
drwxrwxr-x  2 user user 4096  5月 30 00:53 c
lrwxrwxrwx  1 user user    1  5月 30 01:04 d -> c

# 
# カレントディレクトリをdに移したときに
#
$ cd d

#
# pwdとして出てくるのは/home/user/dだが
#
$ pwd
/home/user/d

#
# その内容は/home/user/cと同じ
#
$ ls
c-a

/etc/rc.d/rc?.d/

ここまできてやっとデーモンの起動に話が進みます。initプロセスは続けて/etc/rc.d/rcというシェルスクリプトを実行するのですが、このスクリプトがデーモンを起動しています。ランレベル5の場合/etc/rc.d/rc5.d/の内容に応じてどのデーモンが起動されるかどうかが決まるのですが、この/etc/rc.d/rc?.d/以下をいじることがntsysvの本質なのです。

$ ls -F /etc/rc.d/rc5.d/
K01yum@             K50netdump@          S05kudzu@       S15mdmonitor@   S55sshd@        S95atd@
K02NetworkManager@  K73ypbind@           S06cpuspeed@    S18rpcgssd@     S56rawdevices@  S96readahead@
K05saslauthd@       K74nscd@             S08iptables@    S19rpcidmapd@   S56xinetd@      S97messagebus@
K10psacct@          K74ntpd@             S09isdn@        S19rpcsvcgssd@  S80sendmail@    S97rhnsd@
K12FreeWnn@         K85mdmpd@            S09pcmcia@      S25netfs@       S85gpm@         S98cups-config-daemon@
K20nfs@             K89netplugd@         S10network@     S26apmd@        S87iiim@        S98haldaemon@
K24irda@            K90bluetooth@        S12syslog@      S28autofs@      S90canna@       S99local@
K30spamassassin@    K94diskdump@         S13irqbalance@  S40smartd@      S90crond@
K35vncserver@       K99microcode_ctl@    S13portmap@     S44acpid@       S90xfs@
K35winbind@         S04readahead_early@  S14nfslock@     S55cups@        S95anacron@

このディレクトリの中には「KまたはS + 数字2桁」で始まるシンボリックリンクがあり、これらのリンクは/etc/init.d中の起動スクリプトに向かって張られています。/etc/rc.d/rcは「S」で始まる物について順番にstartオプションを付けて実行することでデーモンを起動していきます。言い換えれば「このディレクトリ中に起動スクリプトに対してSで始まるシンボリックリンクを作成すれば、それが自動的に起動される」ということです。「K」で始まる場合はその逆、停止を意味します。

もうお分かりでしょうか。ntsysvでのチェックのオンオフは、ここのシンボリックリンクの変更を意味しているのです。

ランレベル5に対して/etc/rc.d/rc5.d/が対応するように、ランレベルに応じて1つのディレクトリがこのために割り当てられています。ntsysvではランレベルごとの設定一覧を見ることは出来ませんが、chkconfigコマンドに--listオプションを与えるとそれらをまとめてみることが出来ます。

syslog

ここまででデーモンの一般論は終わりです。ここからはデーモンの働きについて個別に見ていきます。

syslogデーモン(syslogd)はその名の通りシステムのログ(記録)処理を担当するデーモンです。これまで説明したように
デーモンは裏で動くため、動作中にエラーが起きたときなどにメッセージを出力してユーザーに伝えるということができません。
そのために多くのデーモンは自身のログをsyslogを経由してファイルに書き込みます。これによってユーザーはシステムがきちんと動作しているか確認できるようになっているのです。

syslog.conf

syslogの設定ファイルは/etc/syslog.confです。そのフォーマットについてはここでは触れませんが、それを知らなくても「どのファイルに記録されるか」ということは見れば分かるようになっています。最初は/var/log/messages、/var/log/cronあたりを押さえておけば十分でしょう。

ログの重要性

もしもこのような現象に見舞われてしまったら、どうしようかと途方にくれる前にまずはログを確認する習慣をつけてください。ログは貴重な情報の宝庫です。多くの場合ログを見ることで何かしらの手がかりを得ることができますし、自分では出力されたログの意味が分からなくてもそのメッセージをキーワードにして検索エンジンで探すことで必要な情報を手に入れられることもあります。

cron

cronは指定した時刻にコマンドを自動的に実行するためのデーモンです。デスクトップ用途でLinuxを使う場合にはあまり恩恵を受けることはありませんが、サーバー用途の場合は多くの局面で役に立ちます。

/etc/crontab

cronの設定にはいくつかの方法がありますが、その中で基本となっているのが/etc/crontabです。このファイルの末尾の部分に次のような設定があります。

01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

空白で区切られた各フィールドはそれぞれ

  1. 曜日
  2. 実行する際のユーザー権限
  3. コマンド

を表すので、結局これらの行は上から順に

  1. 毎時1分にroot権限で「run-parts /etc/cron.hourly」というコマンド(/etc/cron.hourly以下にある実行ファイルを動かす)を実行
  2. 毎日4時2分にroot権限で「run-parts /etc/cron.daily」を実行
  3. 毎週日曜日の4時22分にroot権限で「run-parts /etc/cron.weekly」を実行
  4. 毎月1日の4時42分にroot権限で「run-parts /etc/cron.monthly」を実行

するということを意味します。フォーマットの詳細はcrontab(5)で調べることができます。

crontab

/etc/crontabでの設定はcronをシステム管理に使うためのものでしたが、個人的な用途にもcronを使うことができます。もちろんパーミッションの都合で/etc/cron.*にファイルを配置することはできないので、代わりにcrontabというコマンドを使って設定します。

オプション意味
-e 編集
-l 一覧

このときに利用するフォーマットは/etc/crontabと基本的に同じですが、実行するユーザーの指定がいらなくなります。たとえばcron.yearlyのようなものを定義したい場合は

$ crontab -e
42 4 1 1 * run-parts /etc/cron.yearly

と編集してから保存します。