Fluentd on Solaris 10/11

このところ話題のログ収集ソフトウェア FluentdSolaris 10/11 で動かしてみたメモです。
RedhatDebian だと td-agent というパッケージが用意されていて、yum や apt でインストールできますが、Solaris には公式のパッケージがないのでソースからインストールしました。

事前準備

Solaris 11 の場合、gcc をインストールしてください。

$ sudo pkg install gcc-45

Solaris 10 の場合、gcc と make が使えるように PATH を通してください。

$ export PATH=$PATH:/usr/sfw/bin:/usr/ccs/bin

Ruby インストール

Fluentd は Ruby で作られているので、Ruby が必要になります。Fluentd 10.0.42 の時点で、Ruby 1.9 系にしか対応していないので、Ruby 1.9.3 をインストールすることにします。(2014-02-16追記: Ruby 2.1.0 でも動きました。)
td-agent のパッケージには Ruby が含まれているので、それに倣って /opt/fluentd 配下に Fluentd 専用の Ruby をインストールすることにします。

Rubyの公式サイトからtarボールをダウンロードします。

$ wget http://cache.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p484.tar.gz
  または
$ wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.0.tar.gz

tarボールを展開します。

$ gtar zxvf ruby-*.tar.gz
$ cd ruby-*

インストール先を /opt/fluentd 配下にします。

$ ./configure --prefix=/opt/fluentd  # Ruby 1.9.3 の場合
$ ./configure --prefix=/opt/fluentd CFLAGS='-std=gnu90'  # Ruby 2.1.0 の場合

コンパイルします。

$ make
$ sudo make install

(2014-02-16追記) Ruby 2.1.0 だと、gem で msgpack 0.5.8 がうまくインストールできなかったので、対応してないと勘違いしていましたが、↓の記事を参考に ruby の configure 時に CFLAGS='-std=gnu90' を追加したらインストールできました。
Solaris10上のRuby 2.0.0(というか、OpenCSWのgcc-4.8.0)でmsgpackがインストールに失敗する件 - Qiita

Fluentd インストール

gemを使うので、必要に応じて HTTP Proxy を設定します。

$ export http_proxy=http://proxy:port

(2014-03-08追記) cool.io 1.2.0 が SPARCSolaris でインストールに失敗するので、1.1.1 をインストールします。

$ sudo /opt/fluentd/bin/gem install cool.io --version '=1.1.1' 

gemでインストールします。

$ sudo /opt/fluentd/bin/gem install fluentd

必要に応じて、プラグインをインストールします。

$ sudo /opt/fluentd/bin/gem install \
    fluent-plugin-file-alternative \
    fluent-plugin-parser \
    fluent-plugin-rewrite

設定とログ用のディレクトリを作成します。

$ cd /opt/fluentd
$ sudo mkdir conf logs

設定

設定ファイルを /opt/fluentd/conf/fluentd.conf として作成します。


    type forward



    type file
    path /tmp/fluentd_debug.log

起動スクリプト

起動スクリプトを /lib/svc/method/fluentd として作成します。

#!/bin/bash

# init script for fluentd

. /lib/svc/share/smf_include.sh

export PATH=/opt/fluentd/bin:$PATH

SERVICE=fluentd
BASEDIR=/opt/fluentd
INSTANCE=`basename $0`
CONFFILE=$BASEDIR/conf/$INSTANCE.conf
LOGFILE=$BASEDIR/logs/$INSTANCE.log

PIDDIR=/var/run/$SERVICE
PIDFILE=$PIDDIR/$INSTANCE.pid

RETVAL=0

case "$1" in
start)
    [ ! -d $PIDDIR ] && mkdir -p $PIDDIR
    $0 configtest && $SERVICE -c $CONFFILE -d $PIDFILE -l $LOGFILE
    RETVAL=$?
    ;;
stop)
    if [ -f $PIDFILE ]; then
        kill `cat $PIDFILE`
        if [ $? -eq 0 ]; then
            rm -f $PIDFILE
        fi
    else
        echo "'$PIDFILE' does not exist!"
    fi
    ;;
refresh)
    $0 configtest && kill -HUP `cat $PIDFILE`
    ;;
reopen)
    kill -USR1 `cat $PIDFILE`
    ;;
configtest)
    $SERVICE -c $CONFFILE --dry-run -q
    RETVAL=$?
    ;;
*)
    echo "Usage: $0 {start|stop|refresh|configtest}"
    RETVAL=1
    ;;
esac

exit $RETVAL

実行権限を付けます。

$ sudo chmod 755 /lib/svc/method/fluentd

Solaris では LIBEV_FLAGS=3 という環境変数を設定しないと起動しないようです。(LIBEV_FLAGS=3 を設定すると、event ports が無効になります。event ports は超バギーらしいです。。。 http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Event_port_backend)

(2014-02-22追記) cool.io 1.1.0 の対応で、libev のバージョンが4.04になり、LIBEV_FLAGS=3 は不要になったようです。というか、event ports は使われなくなった模様。

SMF登録

SMFのマニフェストファイルを /lib/svc/manifest/site/fluentd.xml として作成します。

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">

<service_bundle type='manifest' name='fluentd'>

<service
        name='site/fluentd'
        type='service'
        version='1'>

        <instance name='default' enabled='false'>
                <!--
                  Wait for network interfaces to be initialized.
                -->
                <dependency name='network'
                    grouping='require_all'
                    restart_on='error'
                    type='service'>
                    <service_fmri value='svc:/milestone/network:default'/>
                </dependency>

                <!--
                  Wait for all local filesystems to be mounted.
                -->
                <dependency name='filesystem-local'
                    grouping='require_all'
                    restart_on='none'
                    type='service'>
                    <service_fmri
                        value='svc:/system/filesystem/local:default'/>
                </dependency>

                <exec_method
                        type='method'
                        name='start'
                        exec='/lib/svc/method/fluentd start'
                        timeout_seconds='60' />

                <exec_method
                        type='method'
                        name='stop'
                        exec='/lib/svc/method/fluentd stop'
                        timeout_seconds='60' />

                <exec_method
                        type='method'
                        name='refresh'
                        exec='/lib/svc/method/fluentd refresh'
                        timeout_seconds='60' />

                <property_group name='startd' type='framework'>
                        <!-- sub-process core dumps shouldn't restart session -->
                        <propval name='ignore_error' type='astring' value='core,signal' />
                </property_group>

        </instance>

        <stability value='Evolving' />

</service>

</service_bundle>

サービスを登録します。

$ sudo svccfg -v import fluentd.xml

サービスを起動します。

$ sudo svcadm enable fluentd

サービスが正常に起動していることを確認します。

$ svcs fluentd
STATE          STIME    FMRI
online         12:31:50 svc:/site/fluentd:default

動作確認

fluent-cat コマンドを使って動作確認します。タグを指定して、標準入力からJSONを入力すると Fluentd に送信されます。終了するには Ctrl+D を入力してください。

$ /opt/fluentd/bin/fluent-cat debug.test
{ "test" : "debug" }
Ctrl+D

上記の設定では、↓のようにファイルに出力されていれば成功です。

$ cat /tmp/fluentd_debug.log.*
20XX-XX-XXTXX:XX:XX+09:00       debug.test      {"test":"debug"}

Solaris 10 対応

Solaris 10 で out_forward プラグインを使うと、以下のようなエラーが出て送信することができませんでした。

[warn]: temporarily failed to flush the buffer. next_retry=2014-01-16 10:00:38 +0900 error_class="Errno::ENOPROTOOPT" 
error="Option not supported by protocol" instance=4227828
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/plugin/out_forward.rb:227:in `setsockopt'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/plugin/out_forward.rb:227:in `send_data'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/plugin/out_forward.rb:141:in `block in write_objects'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/plugin/out_forward.rb:135:in `times'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/plugin/out_forward.rb:135:in `write_objects'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/output.rb:445:in `write'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/buffer.rb:296:in `write_chunk'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/buffer.rb:276:in `pop'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/output.rb:306:in `try_flush'
[warn]: /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/output.rb:131:in `run'

調べてみると、Solaris 10 の sockopts が SO_SNDTIMEO をサポートしていないようだったので、該当箇所をコメントアウトしたところ動作するようになりました。Solaris 11 ではこの修正は不要でした。

$ cd /opt/fluentd/lib/ruby/gems/1.9.1/gems/fluentd-0.10.42/lib/fluent/plugin
$ diff out_forward.rb.orig out_forward.rb
227c227,228
<         sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, opt)
    • -
> # SO_SNDTIMEO does not work on Solaris > #sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, opt)