VPSを使ってネームサーバ構築

今までバリュードメインの無料ネームサーバを利用していたのですが、ご存知の状況でして・・・。この際自分で作ってしまおうと思ったわけです。

まず、サーバをどうしようかなと思いました。自分で構築するのであれば、もちろんroot権限がある専用サーバが必要です。安いものだとさくらインターネットの月額7800円のもの。スペックはネームサーバを構築するならば十分です。一つ気になるといえば、HDDが冗長化されていないくらいでしょうか?RAID1のプランだと初期が一気に高くなるので厳しいです。

自宅サーバでもいいかなと思いましたが、プライマリのサーバを置いておくのはちょっと心配な気もします。もうちょっと安いレンタルはないかなと思い、VPNとやらを調べてみることにしました。

感想は思ったより高くてびっくりってな感じです。これなら専用サーバ借りたほうがいいんではと思えるほどです。しかも制限が厳しくて使いづらそうです。Pleskとかもいらないですし、評判もすこぶる悪い。海外サーバを再販しているようなところも多くて、これなら海外で借りたほうがいいんではと思い、調べてみると日本とは比べて安いしいい感じです。

色々調べた結果Linodeというところにしました。一番安い$19.95のものを選択。クレジットカードで登録後、すぐに使えるようになりました。スバラシイです。
Webからコンソールで操作できますし、ディストリビューションも選択できて申し分ないです。しかもIPアドレスの逆引きにも対応しています。

ちょっと気になったのはネームサーバって最初にプライマリに問い合わせて、ダウンしてたらセカンダリにいってと考えていたので、海外にネームサーバがあるとレスポンスが悪くなったりするのかと心配でした。
かなり常識的なことなのかもしれませんが、距離や応答速度などから最適なネームサーバに問い合わせをしてくれるらしい。ということは、セカンダリを日本に置いておけばそっちにいくってことかな?
下記のような構成でいくことにしました。

プライマリDNS => Linode
セカンダリDNS => 自宅サーバ

ディストリはCentOSにしてしまったのですが、今思えばDebianとか他のにすればよかった・・・。さっそく起動してsshを認証鍵のみにして、不要なデーモンを止めました。ふと、気づいたのですがlocaleの設定が日本になってないみたい。

## /etc/sysconfig/i18n
# 下記のように変更して再ログイン
LANG="ja_JP.UTF-8"

時間もまだズレている・・・。そうか、タイムゾーンが日本になっていないか。タイムゾーンは、/etc/localtimeで管理されているので、日本(東京)のもので上書きします。

# cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

ネームサーバは、bind9を使おうと思います。昨今色々な問題点が出てきているのでちょっと心配ではあるのですが、以前にちょっとだけいじったこともあったので今回はこれを使ってみます。
その前にファイアウォールの設定をします。

## ルールのクリア
# iptables -F
## ポリシー設定
## OUTPUTは全て許可、FORWARDは破棄
# iptables -P OUTPUT ACCEPT
# iptables -P FORWARD DROP
## ループバックからは許可
# iptables -A INPUT -i lo -j ACCEPT
## ICMP(ping), DNS, SSHのみ許可
# iptables -A INPUT -p icmp -j ACCEPT
# iptables -A INPUT -p tcp --dport 53 -j ACCEPT
# iptables -A INPUT -p udp --dport 53 -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
## その他は全て破棄
# iptables -P INPUT DROP
# /etc/init.d/iptables save
# /etc/init.d/iptables restart

yumを使い、bindをインストールします。bind-chrootを使うとchroot環境で動作するらしいです。安全のためにchrootを使ってみます。caching-nameserverは一度問い合わせた内容をキャッシュすることで高速に動作させることができるそうです。

# yum install bind bind-chroot caching-nameserver

bindの設定をします。rndcを利用すると権限のないユーザなどから、bindの制御ができなくなるそうです。chrootなので下記の位置となります。

## 設定ファイルをサンプルからコピー
# cp /var/named/chroot/etc/named.caching-nameserver.conf /var/named/chroot/etc/named.conf
## ゾーンファイルを保存するディレクトリの作成
# mkdir /var/named/chroot/var/named/zones
# chown root:named /var/named/choort/var/named/zones
## /var/named/chroot/etc/named.confを編集
options {
listen-on port 53 { any; };
directory       "/var/named";
dump-file       "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
allow-query     { any; }; # 外部に公開
 # セカンダリDNSに転送を許可
allow-transfer {
192.168.x.1;
192.168.x.2;
};
also-notify {
192.168.x.1;
192.168.x.2;
};
notify yes;
version "unknown";
};
logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};
include "/etc/rndc.key";
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndckey"; };
};
view external {
match-clients { any; };
recursion no;
zone "." {
type hint;
file "named.ca";
};
zone "example.com" {
type master;
file "zones/example.com.zone";
};
};

次にルートネームサーバの情報を更新します。

# dig @a.root-servers.net . ns > /var/named/chroot/var/named/named.ca

ゾーンファイルを作ります。

## /var/named/chroot/var/named/zones/example.com.zone
; example.com
$TTL    300 # 5分に設定、短すぎ?
@       IN      SOA     ns1.example.com. root.ns1.example.com. (
2009080701      ; Serial # シリアル番号、いじったらここも更新
300             ; Refresh # ゾーン転送の間隔
120             ; Retry # 失敗した場合の試行時間
3600000         ; Expire # 有効期限
3600 )          ; Minimum # ネガティブキャッシュの保持期間
IN      NS      ns1.example.com.
IN      NS      ns2.example.com.
IN      NS      ns3.example.com.
ns1             IN      A       192.168.x.10
ns2             IN      A       192.168.x.1
ns3             IN      A       192.168.x.2
www             IN      A       192.168.x.5

bindが無事に起動すれば成功です。ついでに定期的にルートネームサーバを更新するようにします。

## /usr/local/etc/shells/update_named_ca.sh
#!/bin/sh
NAMED_CA=/var/named/chroot/var/named/named.ca
dig @a.root-servers.net . ns > $NAMED_CA

Cronで一日一回実行します。

# chmod 700 /usr/local/etc/shells/update_named_ca.sh 
## Cronに登録
02 4 * * * /usr/local/etc/shells/update_named_ca.sh > /dev/null 2>&1

参考サイト
404 Not Found
bind9 設定
3 Minutes Networking No.68

Scribeでログの集約・収集【追記】

あとがきでログを取る際の負荷が高いということを書いたのですが、もう一つのWebサーバ(lighttpd)でもログを取るようにしたところ、あまりにもレスポンスが遅くなってしまったので、Pythonで書き直してみました。といってもサンプルファイルをちょっといじっただけ・・・。

## /usr/local/bin/scribe_httpd2
#!/usr/bin/python
import sys
from scribe import scribe
from thrift.transport import TTransport, TSocket
from thrift.protocol import TBinaryProtocol
if len(sys.argv) == 2:
category = sys.argv[1]
host = '127.0.0.1'
port = 1463
elif len(sys.argv) == 4 and sys.argv[1] == '-h':
category = sys.argv[3]
host_port = sys.argv[2].split(':')
host = host_port[0]
if len(host_port) > 1:
port = int(host_port[1])
else:
port = 1463
else:
sys.exit('usage (message is stdin): scribe_cat [-h host[:port]] category')
socket = TSocket.TSocket(host=host, port=port)
transport = TTransport.TFramedTransport(socket)
protocol = TBinaryProtocol.TBinaryProtocol(trans=transport, strictRead=False, strictWrite=False)
client = scribe.Client(iprot=protocol, oprot=protocol)
transport.open()
while 1:
message = sys.stdin.readline()
log_entry = scribe.LogEntry(dict(category=category, message=message))
result = client.Log(messages=[log_entry])
transport.close()

scribe_httpdを置き換えるだけで動作しますが、lighttpdの場合ログ用のプロセスは終了してくれないようなので自分で終了させる必要がある?ようです。たぶんスクリプトの書き方がおかしいんだと思います。ループしてるところで終了イベントを拾って処理してあげたりする必要があるのかな・・・?よくわからないので下のようにして強引に。

killall scribe_httpd2

これでだいぶレスポンスが早くなりました。

Scribeでログの集約・収集【後編】

いよいよWebサーバのログをScribeを通して処理してみます。examplesディレクトリに入っていた、scribe_catとscribe_ctrlはそのまま使えそうなのでこれを利用してみます。

# cp examples/{scribe_cat,scribe_ctrl} /usr/local/bin/

まず、ログサーバ(ログを集約するサーバ)の設定をします。このサーバに各Webサーバのログが書き込まれていきます。設定ファイルは/usr/local/etc/scribeの下に置くものとします。

# mkdir /usr/local/etc/scribe
# mkdir /var/log/scribe
# touch /usr/local/etc/scribe/scribed.conf

ログサーバの設定ファイル(scribed.conf)の内容は下記になります。

port=1463 # 待ち受けポート
max_msg_per_second=2000000 # 一秒間に受け取るメッセージ数
check_interval=3 # チェックする間隔(Store)
# Web server
<store>
category=www* # wwwではじまるカテゴリを処理
type=buffer # buffer storeを利用
target_write_size=20480 # バッファサイズ(これ以上溜まると書き出す)
max_write_interval=1 # 書き出す間隔(バッファサイズに依存せずに一定期間で処理する間隔)
buffer_send_rate=2 # 処理する間隔
retry_interval=30 # primaryに失敗してからのリトライ間隔
retry_interval_range=10 # リトライ間隔の幅(この幅でランダムに試行する)
<primary>
type=file # file storeを利用
fs_type=std # stdのみサポート
file_path=/home/www/logs # ログを書き出す場所
base_filename=access_log # ログファイル名
max_size=100000000 # ローテート最大サイズ
rotate_period=daily # ローテート間隔(daily=日ごと)
rotate_hour=0 # 何時にローテートするか(0時)
rotate_minute=5 # 何分にローテートするか(5分)
add_newlines=1 # 改行するか(1=する)
create_symlink=true # 最新ファイルへのシンボリックリンクを設定
</primary>
# primaryの書き込みに失敗した場合の予備
<secondary>
type=file
fs_type=std
file_path=/tmp
base_filename=access_log
max_size=3000000
</secondary>
</store>
# 処理されなかったメッセージの保存先
<store>
category=default # defaultにすると処理されなかったものがくる
type=buffer
target_write_size=20480
max_write_interval=1
buffer_send_rate=2
retry_interval=30
retry_interval_range=10
<primary>
type=file
fs_type=std
file_path=/var/log/scribe
base_filename=scribed.log
max_size=1000000
</primary>
<secondary>
type=file
fs_type=std
file_path=/tmp
base_filename=scribed.log
max_size=3000000
</secondary>
</store>

scribedの起動スクリプトは下記のようなものを作りました。

#!/bin/sh
#
# Scribed     Startup script for the scribe daemon
#
# chkconfig: - 83 13
# description: Scribed.
#
# processname: scribed
# config: /usr/local/etc/scribe/scribed.conf
# pidfile: /var/run/scribed.pid
#
# Source function library
. /etc/rc.d/init.d/functions
if [ -f /etc/sysconfig/scribed ]; then
. /etc/sysconfig/scribed
fi
if [ -z "$SCRIBED_CONF_PATH" ]; then
SCRIBED_CONF_PATH="/usr/local/etc/scribe/scribed.conf"
fi
prog="scribed"
lockfile="/var/lock/subsys/$prog"
scribed="/usr/local/bin/scribed"
scribe_ctrl="/usr/local/bin/scribe_ctrl"
RETVAL=0
start() {
echo -n $"Starting $prog: "
$scribed -c $SCRIBED_CONF_PATH > /dev/null 2>&1 &
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
success
touch $lockfile
fi
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $scribed
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $lockfile
return $RETVAL
}
status() {
$scribe_ctrl status
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
RETVAL=1
esac
exit $RETVAL

次にWebサーバ(ログの送信元サーバ)の設定をします。設定ファイルの保存先や起動スクリプトなどはログサーバと同じです。今回は念のためにログをネットワーク先(ログサーバ)とローカル二つに保存することにします。

port=1463
max_msg_per_second=2000000
check_interval=3
# Web server
<store>
category=www*
type=multi # multi storeネットワークとローカルで保存
target_write_size=20480
max_write_interval=1
# ネットワーク保存
<store0>
type=network # ネットワーク転送する
remote_host=192.168.1.2 # 転送先ホスト
remote_port=1463 # 転送先ポート
</store0>
# ローカル保存
<store1>
type=file
fs_type=std
file_path=/home/www/logs
base_filename=access_log
max_size=100000000
rotate_period=daily
rotate_hour=0
rotate_minute=5
add_newlines=0
create_symlink=true
</store1>
</store>
<store>
category=default
type=buffer
target_write_size=20480
max_write_interval=1
buffer_send_rate=2
retry_interval=30
retry_interval_range=10
<primary>
type=file
fs_type=std
file_path=/var/log/scribe
base_filename=scribed.log
max_size=1000000
</primary>
<secondary>
type=file
fs_type=std
file_path=/tmp
base_filename=scribed.log
max_size=3000000
</secondary>
</store>

設定は以上です。両方のサーバでscribedが正常に起動できるか確認してください。次にWebサーバとなるApacheのログ出力をファイルから、Scribeへの出力に切り替えます。とりあえず、エラーログはそのままファイルへと出力、アクセスログをScribeに出力することにします。

パイプを使いScribeに渡すことになりますが、scribe_catにそのまま渡すだけではうまく動きませんでした。どうやらパイプを渡す先のプログラムをプロセス上にあげておく必要があるようです。(おそらくログ出力の負荷を減らすため?)
scribe_httpdというシェルプログラムを作り、その中で標準出力を受けながらループすることにしました。

## /usr/local/bin/scribe_httpd
## このシェルプログラムからscribe_catへ渡す
#!/bin/sh
while /bin/true
do read line
echo $line | /usr/local/bin/scribe_cat $1
usleep 100000
done

上記のシェルプログラムを使い、パイプ経由でログを出力します。

# httpd.confまたはextra/httpd-vhosts.confなど
<VirtualHost *:80>
ServerName www.example.com
DocumentRoot "/home/www.example.com/public_html"
# ErrorLogはファイルに出力
ErrorLog "/home/www/logs/www.example.com/error_log"
# CustomLogはパイプを使ってScribeに出力
CustomLog "| /usr/local/bin/scribe_httpd www.example.com" combined
</VirtualHost>

ちゃんとScribe経由で出力されたのですが一つ問題が・・・。負荷がけっこう高いようです。scribe_httpdがログ出力の個数分プロセスに立ち上がるようなので、バーチャルホストの数やアクセスが増えたらたいへんそうです。CPUの負荷が高いようなので適当に作ったシェルスクリプトがやばいんでしょうか?毎回scribe_catを呼び出すというようなことをせずに、直接Scribeにログを渡すような形にしてやれば、負荷もけっこう下がりそうです。

無事に成功?ということでこれで終わりにしたいと思います。いまさらですが、ScribeでWebサーバのログを集約するのはあまり向かないような気も・・・。しばらく運用してみて問題がおきたら報告していきたいと思います。

Scribeでログの集約・収集【中編】

前編ではScribeのインストールと動作確認までおこないました。実際にWebサーバのログをScribeで処理していくわけですが、その前にネットワークを経由して正常にログの受け渡しができるかどうかを調べていきます。

別のサーバにもScribeをインストールして試したほうがいいのですが、今回はローカル内にポートを変えて二つのscribedを起動して検証します。

## ログサーバ側と仮定 ###
## 今回は設定サンプルのcentralというのを使ってみる 
$ mkdir /tmp/scribetest
$ /usr/local/bin/scribed examples/example2central.conf
## Webサーバ側と仮定 ###
## 別のシェルから同じように設定ファイルを変えて立ち上げる
$ mkdir /tmp/scribetest2
$ /usr/local/bin/scribed examples/example2client.conf
## 別シェルからWebサーバ(ポート1464)に向けて、メッセージを送信
## -h オプションで送信先を指定できる
$ echo "web server message." | ./examples/scribe_cat -h localhost:1464 log
## Webサーバ側で下記のようなメッセージが出力される
## ログサーバにメッセージが送信された
[Thu Jul 30 19:37:50 2009] "Successfully sent <1> messages to remote scribe server <localhost:1463>"
## メッセージを受信できたか調べる
$ cat /tmp/scribetest/log/log_current
web server message.
## ログサーバ(ポート1463)を停止してみる
# ./examples/scribe_ctrl stop 1463
## 次に停止してるログサーバに向けてメッセージを送信
$ echo "hello tokyo." | ./examples/scribe_cat -h localhost:1463 log
## 次のようなメッセージを出力
[Thu Jul 30 19:40:38 2009] "Failed to send <1> messages to remote scribe server <localhost:1463> error <No more data to read.>"
Thrift: Thu Jul 30 19:40:38 2009 TSocket::open() error on socket (after poll) <Host: localhost Port: 1463>Connection refused
[Thu Jul 30 19:40:38 2009] "failed to open connection to remote scribe server <localhost:1463> thrift error <socket open() error: Connection refused>"
[Thu Jul 30 19:40:38 2009] "[log] Opened file </tmp/scribetest2/log/log_00000> for writing"
[Thu Jul 30 19:40:38 2009] "[log] choosing new retry interval <29> seconds"
[Thu Jul 30 19:40:38 2009] "[log] Changing state from <STREAMING> to <DISCONNECTED>"
## ログサーバを復帰させる
$ /usr/local/bin/scribed examples/example2central.conf
[Thu Jul 30 19:42:36 2009] "Opened connection to remote scribe server <localhost:1463>"
[Thu Jul 30 19:42:36 2009] "[log] Changing state from <DISCONNECTED> to <SENDING_BUFFER>"
[Thu Jul 30 19:42:36 2009] "[log] successfully read <1> entries from file </tmp/scribetest2/log/log_00000>"
[Thu Jul 30 19:42:36 2009] "Successfully sent <1> messages to remote scribe server <localhost:1463>"
[Thu Jul 30 19:42:36 2009] "[log] No more buffer files to send, switching to streaming mode"
[Thu Jul 30 19:42:36 2009] "[log] Changing state from <SENDING_BUFFER> to <STREAMING>"
## 復帰したログサーバにメッセージが届いているか確認
$ cat /tmp/scribetest/log/log_current
web server message.
hello tokyo.

無事に成功しました。これでネットワーク経由でログメッセージのやり取りが可能だということがわかりましたので、次は実際にWebサーバのログをやり取りしていきたいと思います。

Scribeでログの集約・収集【前編】

前回の記事で静的ファイルを別サーバから配信することにしましたが、今度はアクセスログがサーバ毎に分散してしまうので、少々やっかいだなと思いました。
出来るだけ正確でリアルタイムに近い形でログを収集できればいいなという感じです。

まず、考えていたのは一定期間毎に一つのサーバにログを収集していく方法です。せっかくlsyncdも入れているので、rsyncで収集するのが一番簡単そうです。しかし、lsyncdでそのままログファイルをミラーしてしまうと、ログが書き込まれる度に送信しちゃうわけで。。。この辺りはどうにか出来るとは思いますが、みんなはどうやっているのかちょっと調べてみました。

とりあえず、検索してみたら下記のページが見つかりました。
ログ集約・収集について【syslog – 集約】 – プログラマ 福重 伸太朗 〜基本へ帰ろう〜

どうやら、「集約」と「収集」では意味合いが違う模様。たしかにそうだなと思い、妙に納得してしまうのでありました。こちらに書いてあったのは、syslogやsyslog-ngを使う方法のようです。
「集約」を目的にするとどうしても精度が落ちてしまうらしい、当然に集約するためにログサーバなどに送信するわけで、データが正しく送れる保証はないということです。
それに比べて「収集」は、ローカルに保存されたデータを定期的にログサーバなどに送信するといった感じでしょうか。精度の高いデータを必要する場合は、こちらがいいようです。今回はアクセスログで、ログ解析などを必要とするためにある程度の精度が必要です。

ここでふと思い出したのが、Scribeというものです。知っている方も多いと思いますがFacebookで利用されているログを集約・収集するためのツールです。調べてみた所、けっこういいんじゃないかと思ったので導入してみることにしました。

・中間程度の信頼性がある。通信が失敗したときはローカルに保存し、次に成功したときに自動的に送信してくれる。
・メッセージ構造がシンプル。カテゴリとメッセージ本体のみで保存される。

とりあえず、使ってみることにします。
Thriftというものを使っているらしく、まずこちらを入れてみます。
# ThriftもFacebookが開発したもので、RPCフレームワークらしいです
Apache Thrift

その前にBoost1.36以上に依存しているため新しいものを入れます。今回はRPMで入れる事にしました。yumではインストール出来ませんので、下記サイトを参考にSRPMからインストールします。
Boost 1.37.0のRPMパッケージ作成メモ – torutkの日記

## http://rpm.pbone.net/index.php3/stat/26/dist/32/size/29387914/name/boost-1.37.0-3.fc11.src.rpm からダウンロード
# rpm -ivh boost-1.37.0-3.fc11.src.rpm
## 依存パッケージをインストール
# yum install libicu-devel
## http://www.02.246.ne.jp/~torutk/linux/centos5/packages.html#SEC23 ここにあるファイルで下記ディレクトリのファイルを置き換える
$ /usr/src/redhat/SPECS
$ /usr/src/redhat/SOURCES
# rpmbuild -bb /usr/src/redhat/SPECS/boost.spec
# rpm -Uvh boost-devel-1.37.0-1.i386.rpm boost-1.37.0-1.i386.rpm
## libeventをyumでインストール
## イベント駆動型アーキテクチャを実装するためのライブラリだそうです
# yum install libevent libevent-devel
$ tar zxvf thrift.tgz
$ cd thrift
$ ./bootstrap.sh
## しかし下記のようなエラー
configure.ac:50: error: possibly undefined macro: AC_PROG_MKDIR_P
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
## autoconfが古いと出るみたいなので2.6以上にします
## http://rpm.pbone.net/index.php3?stat=26&dist=42&size=959985&name=autoconf-2.61-2.el4.pp.noarch.rpm からダウンロード
# rpm -Uvh autoconf-2.61-2.el4.pp.noarch.rpm
## thriftディレクトリで再度実行
$ ./bootstrap.sh
$ ./configure && make
# make install
## Thirftの追加パッケージfb303というにも依存しているらしいので
## fb303もインストールしておきます
$ cd thrift/contrib/fb303
$ ./bootstrap.sh
$ ./configure && make
# make install

次に下記のページからScribe本体をダウンロードします。
Scribe | Free Development software downloads at SourceForge.net

$ tar zxvf scribe-version-2.01.tar.gz
$ cd scribe
$ ./bootstarp.sh
$ ./configure && make
# make install

これでインストール完了です。早速使ってみることにします。

## ビルドしたディレクトリ内にある設定ファイルのサンプルを使って起動
$ /usr/local/bin/scribed examples/example1.conf
## こんなエラーが出ました
/usr/local/bin/scribed: error while loading shared libraries: libthrift.so.0: cannot open shared object file: No such file or directory
## Thriftのライブラリが読み込めていないようです
# echo "/usr/local/lib" >> /etc/ld.so.conf
# /sbin/ldconfig
## 再度実行し、成功すると下記のようなメッセージ
$ /usr/local/bin/scribed examples/example1.conf
Thrift: Thu Jul 30 12:44:18 2009 libevent 1.1a method epoll

この状態ではまだデーモンとして立ち上げず、別のシェル上からログメッセージを送信してみます。Scribeのビルドディレクトリ内のexamplesの中にサンプルのプログラムが入っているみたいです。
scribe_catはメッセージを追記、scribe_ctrlはサーバの状態を確認するもののようです。pythonで出来てました。

## 最後のtestの部分がいわゆるカテゴリ
$ echo "hello japan." | ./examples/scribe_cat test
## するとscribedがこんなメッセージを出力しました
[Thu Jul 30 12:48:30 2009] "Exception < boost::filesystem::create_directory: No such file or directory: "/tmp/scribetest/test" > trying to create directory"
[Thu Jul 30 12:48:30 2009] "[test] Failed to open file </tmp/scribetest/test/test_00000> for writing"
[Thu Jul 30 12:48:30 2009] "[test] Opened file </tmp/test/test_00000> for writing"
## どうやら/tmp/scribetestというディレクトリを作っておく必要があるらしい
## 作ってなかったので、/tmp/test以下に自動保存された
$ mkdir /tmp/scribetest
## 自動的にscribedが認識し自動保存されたログを書き込んだ模様
[Thu Jul 30 12:49:38 2009] "[test] Opened file </tmp/scribetest/test/test_00000> for writing"
[Thu Jul 30 12:49:38 2009] "[test] Changing state from <DISCONNECTED> to <SENDING_BUFFER>"
[Thu Jul 30 12:49:38 2009] "[test] successfully read <1> entries from file </tmp/test/test_00000>"
# ちゃんと書き込まれている
$ cat /tmp/scribetest/test/test_current
hello japan.

とりあえず、無事に動いているようでインストール成功しました。長くなりそうなので記事を別けて掲載します。次の記事ではネットワーク経由でログを出力させてみようと思います。

lsyncdで簡単サーバー間ミラーリング

サーバ間のデータミラーリングについて調べてみました。
僕がやりたかったのは「別のサーバにデータをコピーしたい」ということでした。
もう一つ条件があります。「簡単」にやりたい。

データのバックアップのためとか、冗長化という意味合いもあると思うのですが、画像などの静的ファイルのみ別のサーバから配信することにします。
ちょっとやっかいなことが、静的ファイルを生成するタイミングがバラバラということです。そして、すぐに別のサーバから配信されるようにしたいというのもありました。

NFSrsync、Unisonなどを使おうと考えていましたが、リアルタイムとなるとけっこう難しいものがあると思います。NFSだとちょっと設定や安定性が不安というのも・・・。あと遠隔地など物理的に距離があると難しそうです。

rsyncやUnisonでリアルタイムに出来るのかな?と思いましたが、調べてみるとlsyncdというものを見つけました。
これはrsyncを使ったものなのですが、Linuxのinotify機能というものを使い、ファイル更新時にリアルタイムでrsyncを実行する事が出来るそうです。なんとスバラシイのでしょうか。

inotify機能について
404 – エラー: 404

今回はこのlsyncdを使ってみようと思います。
使い方はいたって簡単です。まず二つのサーバ(ミラー元とミラー先)にrsyncをインストールします。CentOSを使っていたのでyumを使いました。

# yum install rsync 

まずはミラー先のサーバを設定します。

# /usr/local/etc/rsyncd.conf を作成。設定内容は下記。
# /etc/rsyncd.conf がある場合はそちらのほうがいいかも。
# chrootしない。/etc/localtime が参照できないため、ログの時間がズレる
# chroot先に/etc/localtime を作ってもOK
use chroot = no
# ログの保存先
log file = /var/log/rsyncd.log
# モジュール名
[www]
# rsyncを動かすときのユーザとグループ
uid = nobody
gid = nobody
# ミラー先のパス
path = /home/rsync
# ローカルのみ許可
hosts allow = 192.168.1.0/24
# 書き込み許可
read only = no

パスワードの設定などもできますが使用する場合は、読み込みの権限など気をつけた方がいいかもしれません。
あとは、rsyncdに設定ファイルを読み込ませて起動します。起動ファイルがない場合は下記参照。

#!/bin/sh
# Rsyncd This shell script takes care of starting and stopping the rsync daemon
# description: Rsync is an awesome replication tool.
#
# chkconfig: 345 87 87
# description: Rsync is an awesome replication tool.
# Source function library.
. /etc/rc.d/init.d/functions
[ -f /usr/bin/rsync ] || exit 0
start() {
action "Starting rsyncd: " /usr/bin/rsync --daemon --config=/usr/local/etc/rsyncd.conf
}
stop() {
action "Stopping rsyncd: " killall rsync
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 1
start
;;
*)
echo "Usage: rsyncd {start|stop|restart}"
exit 1
esac
exit 0

次にミラー元サーバの設定をします。下記からlsyncdをダウンロードします。

lsyncd –

Lsyncd (Live Syncing Daemon) synchronizes local directories with a remote targets – Google Project Hosting

$ tar zxvf lsyncd-1.26.tar.gz
$ cd lsyncd-1.26
$ ./configure && make
# make install
# 展開したディレクトリの中にlsyncd.conf.xmlというサンプルがあるので、
# その設定ファイルを/usr/local/etc/lsyncd.conf.xml に保存
# cp lsyncd.conf.xml /usr/local/etc/

lsyncdの設定をします。設定ファイルはXMLで記述するみたいです。

# オプションが下記のようになっていたので、コメントアウトして次のように変更してみました
#<option text="-lt%r"/>
# rsyncのオプションが使えるらしい
<option text="-avz"/>
<option text="--delete"/>
# <directory>から</directory>のセットで、同期ディレクトリを設定
# いくつでも増やせるみたい
<directory>
# 同期元ディレクトリ
<source path="/home/rsync"/>
# 同期先のサーバとモジュール名を指定
# 192.168.0.2::www/hoge/dir こんな感じにモジュール名の後にもパスが書けます
<target path="192.168.0.2::www"/>
</directory>

あとは起動するとすぐに同期(ミラーリング)が始まる模様。起動ファイルは下記のページを参考にちょっといじってみました。
リアルタイムミラーリングツール導入(lsyncd+rsyncd) – Fedoraで自宅サーバー構築

#!/bin/bash
#
# lsyncd
#
# chkconfig: - 99 20
# description: lsyncd auto start script
start() {
/usr/local/bin/lsyncd --conf=/usr/local/etc/lsyncd.conf.xml
}
stop() {
/bin/kill -9 `/sbin/pidof lsyncd`
until [ -z $(/sbin/pidof lsyncd) ]; do :; done
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
pid=`pidof lsyncd`
if [ $? -eq 0 ]; then
echo "lsyncd (pid $pid) is running..."
else
echo "lsyncd is not running"
fi
;;
*)
echo "Usage: lsyncd {start|stop|restart|status}"
exit 1
esac
exit $?

見事にリアルタイムで同期されていました。安定性などはまだ分かりませんがしばらく使ってみようと思います。
今回はローカル環境でしたので、認証や暗号などは一切しませんでしたが気になる方は、sshなどと併用してみるのもアリだと思います。

ひかりoneギガ得プランの性能とかメールサーバ

前回の記事で無事?に接続出来たわけなので、さっそく回線速度を測ってみました。画像は・・・キャプするの忘れました;;

上りが300Mbps
下りが500Mbps

計測したサイトの限界が500Mbpsと書いてあったので、500Mbps以上出るのかもしれません。予想以上の速度におどろきを隠せません!かなり地域差がでるのでしょうか?
付属のCat5eUTPケーブルを使うと速度が出ないと書いてありましたが、僕の場合は関係なかったみたいです。粗悪品が多いのかな?
そういえば100円ショップでもUTPケーブル売ってました。1m〜3mくらいがあったかな・・・。

実質固定IPアドレスなのでサーバを立てようと思う人もいると思いますが、ちょっと注意が必要かもしれません。
最近は当たり前かもしれないですが、メールを送信する際にSMTPサーバにつながりません。OP25Bというやつです。

そこでプロバイダのメールサーバにリレーしようかと思いました。僕はauone-netなので、まずサイトに接続してメールアドレスを発行しました。
それでSMTPサーバのアドレスを確認したわけですが、こいつを指定してもつながらないわけです・・・。SMTPAuthというやつか?!とか色々考えたのですが、そもそもtelnetで叩いてみても反応がないです。(もちろん、KDDIの回線から)

こんなの
SMTP: msa.ac.auone-net.jp

調べたら中継用のサーバがちゃんと用意されているらしい。サポート対象外らしいです。下のページの一番下のところにありました。
Outbound Port25 Blocking: 迷惑メール対策 | au one net 会員向けサービス | au one net

Sendmailのリレーサーバの指定方法です。

# Sendmail.mc
# 編集後にsendmailをリスタートするだけでOK
define(`SMART_HOST',`smtp:ここに中継用サーバのアドレスを入れる')
# 送信テスト
echo hogehoge | mail -s test [email protected]

参考猫ぐらし: sendmailのデフォルトリレー先の設定