検索
連載

自由な設定が可能な最新リソース制御機能FreeBSDのコレ知ってる?(1)(2/2 ページ)

静かに活躍の場を広げているFreeBSD。そのFreeBSDに昔から搭載されているのに知られることなくお蔵入りしている機能や、新しく開発された機能を取り上げ、紹介していきます。最初のテーマは、ホスティングサービスなどでニーズの高いリソース制御機能です。(編集部)

Share
Tweet
LINE
Hatena
前のページへ |       

RACCT/RCTL rctl(8)で無邪気な学生からシステムを守る

 RACCT/RCTL rctl(8)の適用例として、例えば、情報システム学部に入学した学生にUNIX系OSの利用方法を教える演習というシーンを考えてみよう。

 UNIX系OSは基本的に、要望があった順に与えられ得るリソースを可能な限り割り当てる作りになっている。可能な限りのリソースを割り当てて処理しようとするため、誤った使い方をされるとあまり好ましくない状態に陥る。

 例えばシェルを覚えたての学生は、while :を放って無限にプロセスを生成するスクリプトを無邪気に書いてしまうかもしれない。同じサーバにログインして作業しているほかの学生からすれば、たまったものではない。

 rctl(8)を使えば、次のように簡単に制限をかけることができる。

# rctl -a user:daichi:maxproc:deny=5

 制限された以上のプロセスを生成しようとすると、次のように許可されなくなる。

% sleep 10 &
% sleep 10 &
% sleep 10 &
% sleep 10 &
% sleep 10 &
Cannot fork: Resource temporarily unavailable
% sleep 10 &
Cannot fork: Resource temporarily unavailable
% 

 制限された以上にプロセスを生成しようとすると、「それはダメだ」と拒否される。危なっかしい学生向けにある程度制限をかけておくというのは、システムを壊すことなく動かし続ける上で有益だ。アクション部分にdenyではなくlogを指定すれば、コンソールにログを出力させることもできる。

# rctl -a user:daichi:maxproc:log=5

 コンソールに出力されたログは、dmesg(8)コマンドにオプション-aを指定して実行することでチェックできる。

# dmesg -a

 rctl(8)の出力はkern.*で捕捉できるので、次のようにsyslogd(8)を設定することでログファイルに記録することもできる。まず、/etc/syslog.confに次のようにkern.*をログファイルに出力するための設定を追加する。

    kern.* /var/log/kern.log

 次に、/etc/newsyslog.confにローテーションの設定を追加する。

    /var/log/kern.log 600 7 * @T00 J

 ここまで作業したら、次のように空のログファイルを作成してからsyslogd(8)デーモンを再起動する。

# touch /var/log/kern.log
# chmod 600 /var/log/kern.log
# service syslogd restart

 tail(1)でログファイルをモニタリングしておけば、rctl(8)のlog指定されたルールに抵触したログが記録されるようになる。

# tail -f /var/log/kern.log
Jun 20 15:34:26 parancell kernel: rctl: rule "user:1004:maxproc:log=5" matched by pid 2274 (sh), uid 1004, jail 0
Jun 20 15:34:26 parancell kernel: rctl: rule "user:1004:maxproc:log=5" matched by pid 2275 (sh), uid 1004, jail 0
Jun 20 15:34:27 parancell kernel: rctl: rule "user:1004:maxproc:log=5" matched by pid 2276 (sh), uid 1004, jail 0
Jun 20 15:34:27 parancell kernel: rctl: rule "user:1004:maxproc:log=5" matched by pid 2277 (sh), uid 1004, jail 0

 別の制限をチェックしてみよう。例えば、次のようにrctl(8)コマンドを実行すれば、ユーザーの使用するスタックサイズを50MBに制限できる。

# rctl -a user:daichi:stacksize:log=50m
# rctl -a user:daichi:stacksize:deny=50m

 C言語を覚えたての学生は、メモリを消費しまくるプログラムを楽々と作ってしまうかもしれない。例えば次のようなコードは、100MBものスタックを使用することになる。メモリを消費するコードを記述するのはとても簡単だ。

int
main(void)
{
        char b[104857600];
        long i = 0;
 
        for (i = 0; i < 104857600; i++)
                b[i] = 'b';
 
        return 0;
}

 このコードを、リソース制限がかかった状態でコンパイルして実行すると、次のようにセグメンテーションフォールトが発生してプログラムは途中で終了される。制限がかかっていなければ、問題なく動作して終了する。

% cc mem.c
% ./a.out
Segmentation fault (core dumped)
% 

 rctl(8)ではアクションとしてdeny、log以外に、devctlを指定できる。これはdevd(8)に対して通知を実施する指定で、devd(8)経由で任意の処理を実行することが可能になる。

# sysctl -a user:sasaki:maxproc:devctl=10

 このようにさまざまなことが可能になるが、/etc/devd.confにはrctl(8)向けのサンプルが掲載されており、これが分かりやすい。次のようにPostgreSQLのスワップ絡みで通知が飛んできたら、PostgreSQLを再起動するという設定だ。

 動作させているサービスに何らかの問題が発生したら、あるいは問題が発生したと判断できる状況になれば、自動的に再起動をかける。簡単だが有効な方法といえる(なおこのサンプル、記述が間違っており、このままでは動作しない。actionの行の最後には;が必要)。

# This example works around a memory leak in PostgreSQL, restarting
# it when the "user:pgsql:swap:devctl=1G" rctl(8) rule gets triggered.
notify 0 {
        match "system"          "RCTL";
        match "rule"            "user:70:swap:.*";
        action                  "/usr/local/etc/rc.d/postgresql restart"
};

 例えば、ユーザーがmaxproc関連で通知を送ってきた場合、管理者にその旨をメールで通知させたいならば、次のように記述すればよい。ここでカーネルは、ユーザーIDは把握していてもユーザー名は把握していないので、ruleの項目には「ユーザーID」を指定する点に気を付けておきたい。

notify 0 {
        match   "system"        "RCTL";
        match   "rule"          "user:1004:maxproc:.*";
        action  "/bin/echo daichi_failed | /usr/bin/mail -s daichi_failed root";
};

 ここまで設定したら、devd(8)を次のように再起動する。これでdevd(8)経由でのアクションが可能になる。

# service devd restart

 ただし、問題が発生したときにメールで通知するのは、場合によっては逆に問題を悪化させることもあるので、使用する場合は気を付けたい。

ルールをまとめておく/etc/rctl.confファイル

 rctl(8)で設定した内容は、システムを再起動すればクリアされる。運用に当たっては、設定をまとめてファイルに書いておき、システム起動時に自動的に適用させるようにする方がよい。

 まず、/etc/rc.confファイルに次の設定を追加し、起動時にrctl(8)が実行されるようにする。

rctl_enable="YES"

 ルールは/etc/rctl.confファイルにまとめて記述しておく。例えばこれまでに紹介した内容であれば、次のような設定を/etc/rctl.confファイルに記述しておけばよい。

user:sasaki:maxproc:log=5
user:sasaki:maxproc:deny=10
user:sasaki:maxproc:devctl=10
user:sasaki:stacksize:log=50m
user:sasaki:stacksize:deny=50m

 ここまで設定したら、/etc/rctl.confファイルを編集したあとに、次のようにコマンドを実行することで、/etc/rctl.confファイルの内容を自動的に反映できる。

# service rctl start

 運用時にはこのファイルを主に編集することになるだろう。

Jailに対してリソース制限を実施

 ホスティングサービスを提供している場合には、Jailに対してリソース制限を実施するといっそう便利に使える。例えば次のような設定を/etc/rctl.confファイルに追加する。

jail:1:maxproc:log=10/jail
jail:1:maxproc:deny=10/jail
jail:1:maxproc:devctl=10/jail
jail:1:stacksize:log=100m/jail
jail:1:stacksize:deny=100m/jail

 次のようなJail環境がある場合、上記リソース制限を設定しておけば、Jail内のプロセス上限は10個となる。すると、以下のような動作を確認できるだろう。

# jls
   JID  IP Address      Hostname                      Path
     1  192.168.1.207   a.parancell.ongs.co.jp        /home/jails/a
# jexec 1 /bin/sh
# ps x
 PID TT  STAT    TIME COMMAND
 983  -  SsJ  0:00.01 /usr/sbin/syslogd -s
1036  -  IsJ  0:00.00 /usr/sbin/sshd
1039  -  SsJ  0:00.05 sendmail: accepting connections (sendmail)
1046  -  IsJ  0:00.01 /usr/sbin/cron -s
1976  3  SJ   0:00.01 /bin/sh
1979  3  R+J  0:00.01 ps x
# sleep 10 &
# sleep 10 &
# sleep 10 &
# sleep 10 &
# sleep 10 &
Cannot fork: Resource temporarily unavailable
# sleep 10 &
Cannot fork: Resource temporarily unavailable
# 

 これは、特にホスティングサービスを提供する企業にとっては便利な機能といえる。

cron(8)の代替としてシステムモニタリング

 rctl(8)の機能は、これまでcron(8)で実施してきたシステムモニタリングの代わりとしても使用できる。

 cron(8)を使う場合、定期的にプログラムを実行してモニタリングを実施する必要があるため、その分システムに負荷がかかる。rctl(8)であれば、指定したリソース制限に到達するまで処理は実施されず、同様の処理を軽量に実現できる。

 特に、安定したサービス提供においてrctl(8)+devd(8)が提供する機能は強力だ。安直な方法だが、サービスの再起動には迅速な効果が期待できる。開発したシステムがメモリリークを起こすなんていうのもよくある話だが、そんなとき、手っ取り早い解決方法は再起動だ。rctl(8)+devd(8)はそんなときに、シンプルで強力な方法を提供してくれる。

 今回取り上げたRACCT/RCTL rctl(8)は比較的最近実装された機能なので、まだ知らない人の方が多いのではないかと思う。実に便利な機能なので、ぜひ使ってみてほしい。

Profile

後藤 大地

後藤 大地

オングス代表取締役。@ITへの寄稿、MYCOMジャーナルにおけるニュース執筆のほか、アプリケーション開発やシステム構築、『改訂第二版 FreeBSDビギナーズバイブル』『D言語パーフェクトガイド』『UNIX本格マスター 基礎編〜Linux&FreeBSDを使いこなすための第一歩〜』など著書多数。


Index

連載:FreeBSDのコレ知ってる?

 第1回 自由な設定が可能な最新リソース制御機能

Page 1
 実は知らなかったFreeBSDの「あの機能」
 プロセス単位でリソースを制限、setrlimit(2)
 柔軟な設定が可能なRACCT/RCTL rctl(8)
 RACCT/RCTL rctl(8)の基本的な使い方

Page 2
 RACCT/RCTL rctl(8)で無邪気な学生からシステムを守る
 ルールをまとめておく/etc/rctl.confファイル
 Jailに対してリソース制限を実施
 cron(8)の代替としてシステムモニタリング


Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       
ページトップに戻る