[debian] fluentd を Wheezy へ、公式に忠実にインストールするようにレシピを書いてみた [chef]

ここ数日、インフルエンザ(みたいな)症状に苦しんでるしょっさんです。おはようございます。もうすぐ寝るんですが。

今更ですが、fluentd です。

rsyslogd でいいや、とか思いつつも、収集できないかなしいログをどうしようか悩んでいたら、そんなものが流行っていると聞いてやってきました。しかし、残念なことに、debian の標準パッケージには存在しない逸材。お手軽に試すこともできません。
chef でさらっと書いておけばいいやと思ったら、手順が面倒な宝庫。debian使いには、パッケージ作れば良いじゃんと言われたものの、下手にパッケージつくっといてメンテナンスできないの目に見えてるので、なんとか使える方向に持っていこうと奮闘してみました。

と言うことで、公式の[Installing Fluentd Using deb Package](http://docs.fluentd.org/articles/install-by-deb)どおりにやってみましょう。

#[Before Installing Fluentd](http://docs.fluentd.org/articles/before-install)
さきほどのインストールガイドの前に、ちょっとやっておくべきことがあります。

- Set Up NTP
- Increase Max # of File Descriptors
- Optimize Network Kernel Parameters

##ntpを設定しよう
忠実に書いてある通りにやりましょう。とは言っても、ここでは「ntp設定しとけよ!」としか言われてないので、時刻同期できるように組み込んで入れておけるようにしておきましょう。
流れ的には、`ntpdate` して後、`ntp`いれるながれですね。こう。

```ruby:ntpd.rb
execute "update-ntpdate" do
  command "ntpdate #{node['base']['ntp-server']}"
  action :nothing
end

package "ntpdate" do
  action :install
  notifies :run, 'execute[update-ntpdate]', :immediately
end

package "ntp" do
	action :install
end

service "ntp" do
  action [ :enable, :start ]
  supports :status => true, :restart => true, :reload => true
end
```

ファイル名はご自由に。

1. `ntpdate` パッケージを導入
1. あらかじめ `['base']['ntp-server']` で指定しておいた ntp server あてに時刻同期。
我が家では `attributes` に `default['base']['ntp-server'] = "0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org"`など、確実な同期を目指してがんばってます
1. この辺までうまくいけば `ntp` パッケージを入れて
1. 開始させておけばOK

##ファイルディスクリプタの変更
先に申しあげておくと wheezy は標準で `ulimit -n 1024` です。で、ファイルディスクリプタの最大値を `65535` にしておきましょう。ということです。

ただ、後で起動してみれば分かりますが、`/etc/init.d/td-agent` 内で `ulimit -n 8192` と定義されているので、実際には `65535` ほどの数字は無視されています。ちょっと残念ですが、行く先、更に大きな数値に設定されるかも知れないので、このままいきましょう。

はい、こう。

```ruby:default.rb
template "limits.conf" do
  path "/etc/security/limits.conf"
  source "limits.conf.erb"
  owner "root"
  group "root"
  mode  0644
  variables ({
               :soft => node[:fluentd][:soft],
               :hard => node[:fluentd][:hard]
             })
end
```

`attributes` で、次のように定義してあります。`65535` じゃなくて `16384'とかのキリの良い数字でも良いです。

```ruby:default.rb
default['fluentd']['hard'] = "65535"
default['fluentd']['soft'] = "65535"
```

なお、「再起動せよ!」と書いてありますが、再起動しなくても PAM 通ってくれるので、再起動不要です。たぶん。

##Network カーネルパラメータの定義
次はやっかいです。`sysctl` しないとあかんです。
前に、`postgresql` でもパラメータ定義したのがあったので、それ丸パクリしてきました。
必要なパラメータを、`/etc/sysctl.conf` へ書き出して、`/sbin/sysctl -p` してあげるながれです。
なお、`/etc/sysctl.conf` 内で、すでに `net.ipv4.ip_local_port_range` が定義されていると、これは実行されない仕組みになってます。今回、これだけで定義している場合では関係ないですけれども、他にも似たようなことやって、設定している場合、被らないように気をつけないといけないので、もう少しうまい書き方を募集します。 

```ruby:default.rb
bash "nw_setting" do
  user "root"
  code <<-EOF
    echo 'net.ipv4.tcp_tw_recycle = #{node['fluentd']['tcp_tw_recycle']}' >> /etc/sysctl.conf
    echo 'net.ipv4.tcp_tw_reuse = #{node['fluentd']['tw_reuse']}' >> /etc/sysctl.conf
    echo 'net.ipv4.ip_local_port_range = #{node['fluentd']['local_port_range_from']} #{node['fluentd']['local_port_range_to']}' >> /etc/sysctl.conf
    /sbin/sysctl -p /etc/sysctl.conf
  EOF
  not_if "egrep '^net.ipv4.ip_local_port_range = ' /etc/sysctl.conf"
end
```

これらも、`attributes` に変数定義してあります。

```ruby:default.rb
default['fluentd']['tcp_tw_recycle']        = "1"
default['fluentd']['tw_reuse']              = "1"
default['fluentd']['local_port_range_from'] = "10240"
default['fluentd']['local_port_range_to']   = "65535"
```

こんな感じ。

# Step0: Before Installation
やっと step0 です。長いです。長すぎです。ごめんなさい。

##GPG key

apt のリストを追加するので、gpg鍵を追加しておきます。

```ruby:default.rb
execute "adding-gpg-td" do
  command "curl -L http://packages.treasure-data.com/debian/RPM-GPG-KEY-td-agent | apt-key add -"
  not_if "apt-key list | egrep -q 'Treasure Data'"
end
```

- curl で gpg を拾ってきて、そのまま `apt-key add` する
だけです。
ただ、ムダに何度もやらないように、`not_if` で gpg鍵の登録有無を確認してます。

# Step1 (Ubuntu): Install from Apt Repository
リンク元には「debian/ubuntu」って書いてあるのに、ドキュメント側では「Ubuntu」になっていてアレです。

##Ubuntu Lucid
12.04 向けと 10.04向けとありますが、12.04 向けの場合、`glibc 2.14` が要求されて難儀なので、10.04 向けを選択しました。
ただ、これでも地雷あるんですが。

`curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-lucid.sh | sh`

とありますが、中身を展開しました。従って、当該shell の中身が変更した場合に忠実に追い切れないという欠点があります。ここだけ忠実じゃないです。ゴメンなさい。理由は、ブラックボックスのママだとツライ、が正解です。

sh の中身を展開すると、こうなります。

```bash:install-ubuntu-lucid.sh
echo "This script requires superuser access to install apt packages."
echo "You will be prompted for your password by sudo."

# clear any previous sudo permission
sudo -k

# run inside sudo
sudo sh <<SCRIPT

  # add treasure data repository to apt
  echo "deb http://packages.treasure-data.com/debian/ lucid contrib" > /etc/apt/sources.list.d/treasure-data.list

  # update your sources
  apt-get update

  # install the toolbelt
  apt-get install -y --force-yes td-agent

SCRIPT
```

1. `/etc/apt/source.list.d/treasure-data.list` へ、apt の source リストを追加
1. `apt-get update`
1. `td-agent` を `apt-get install` する

ここで注意。この shell だと、`--force-yes` されちゃってるのがこわいので、ふつーにインストールしてみると 「`libssl0.9.8` がねぇぞ(#ﾟДﾟ)ｺﾞﾙｧ!!」って言われるので、困り果てると思います。困りました。wheezy だと `libssl1.0.0` 入ってるのに。

イロイロ探ってみたら、「squeeze のlibssl0.9.8入れれば良い」とか書いてあって、ホントかよと思って入れてみたらうまくいきました。
しかも、こんな感じで、両パッケージとも導入されます。別パッケージ扱いなのですね(´・ω・`)

```bash:libssl
ii  libssl0.9.8                        0.9.8o-4squeeze14         amd64        SSL shared libraries
ii  libssl1.0.0:amd64                  1.0.1e-2+deb7u4           amd64        SSL shared libraries
```

と言うことで、この辺りを実現してくれるレシピは、こう。

```ruby:default.rb
execute "apt-get-update" do
  command "apt-get update"
  ignore_failure true
  action :nothing
end

template "treasure-data.list" do
  path "/etc/apt/sources.list.d/treasure-data.list"
  owner "root"
  group "root"
  mode  0644
  notifies :run, 'execute[apt-get-update]', :immediately
end

dpkg_package "libssl0.9.8" do
        source "#{Chef::Config[:file_cache_path]}/#{node[:fluentd][:libssl_file]}"
        action :nothing
end

remote_file "#{Chef::Config[:file_cache_path]}/#{node[:fluentd][:libssl_file]}" do
        source node[:fluentd][:libssl_url]
        not_if "dpkg -l | egrep -q 'libssl0.9.8'"
        mode 0644
        notifies :install, 'dpkg_package[libssl0.9.8]', :immediately
end
```

```ruby:treasure-data.list.erb
deb http://packages.treasure-data.com/debian/ lucid contrib
```

1. `apt-get update` する部分です。すぐには実行しません。また、エラーが発生したら、その後、うまく行くはずもないので `ignore_failure true` で撃沈するように定義してます
1. `/etc/apt/sources.list.d/treasure-data.list` を準備してます。`templates` へ `treasure-data.list.erb` を準備してあげてくださいな。で、テンプレートファイルがちゃんと配信できたら、`apt-get update` を「即時」実行します。
1. `libssl0.9.8` というパッケージが存在したら、dpkg -i して上げる設定です。ここでも何もしません。
1. `remote_file` を使って、download してきてます。ちゃんとダウンロードできたら、`dpkg_package` で、「即時」`libssl0.9.8`を導入してあげてます。

`attributes` は、こう。

```ruby:default.rb
# 'td-agent' will need the package of "libssl0.9.8"
default['fluentd']['libssl_url']  = "http://ftp.jp.debian.org/debian/pool/main/o/openssl/libssl0.9.8_0.9.8o-4squeeze14_amd64.deb"
default['fluentd']['libssl_file'] = File.basename(node['fluentd']['libssl_url'])
```

もう、更新されないと思うけど、難儀な部分です。どうしたらいいか、募集中。

最後に `td-agent` のパッケージ導入です。

```ruby:server.rb
package "td-agent" do
  action :install
end

service "td-agent" do
  action [ :enable, :start ]
  supports :status => true, :restart => true
end
```

chef やってる人なら見慣れた光景ですね、コレで完成ですヽ(´ー｀)ノ

# で?
さて、ココまで見てくれた人たちはよく分かると思いますが、どないなってんねん、という感じですね。ファイルバラバラじゃねぇかと。

ということで、最後に、ファイルの構成と、中身をまとめておきます。
最初から素直に、それだけ掲載しておけば良かったんじゃないかという疑念にかられますが、コレで良かったと信じましょう。

```ruby:nodes/fluentd.json
{
    "run_list":[
	"recipe[base]",
	"recipe[fluentd::server]"
    ]
}
```

```ruby:site-cookbook/base/attributes/default.rb
default['base']['ntp-server'] = "0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org"
```

```ruby:site-cookbook/base/recipes/default.rb
execute "apt-get-update" do
  command "apt-get update"
  ignore_failure true
  action :nothing
end

execute "update-ntpdate" do
  command "ntpdate #{node['base']['ntp-server']}"
  action :nothing
end

package "ntpdate" do
  action :install
  notifies :run, 'execute[update-ntpdate]', :immediately
end

package "ntp" do
	action :install
end

service "ntp" do
  action [ :enable, :start ]
  supports :status => true, :restart => true, :reload => true
end
```

```ruby:site-cookbook/fluentd/attributes/default.rb

default['fluentd']['hard'] = "65535"
default['fluentd']['soft'] = "65535"

default['fluentd']['tcp_tw_recycle']        = "1"
default['fluentd']['tw_reuse']              = "1"
default['fluentd']['local_port_range_from'] = "10240"
default['fluentd']['local_port_range_to']   = "65535"

# 'td-agent' will need the package of "libssl0.9.8"
default['fluentd']['libssl_url']  = "http://ftp.jp.debian.org/debian/pool/main/o/openssl/libssl0.9.8_0.9.8o-4squeeze14_amd64.deb"
default['fluentd']['libssl_file'] = File.basename(node['fluentd']['libssl_url'])
```

```ruby:site-cookbook/fluentd/recipes/default.rb
bash "nw_setting" do
  user "root"
  code <<-EOF
    echo 'net.ipv4.tcp_tw_recycle = #{node['fluentd']['tcp_tw_recycle']}' >> /etc/sysctl.conf
    echo 'net.ipv4.tcp_tw_reuse = #{node['fluentd']['tw_reuse']}' >> /etc/sysctl.conf
    echo 'net.ipv4.ip_local_port_range = #{node['fluentd']['local_port_range_from']} #{node['fluentd']['local_port_range_to']}' >> /etc/sysctl.conf
    /sbin/sysctl -p /etc/sysctl.conf
  EOF
  not_if "egrep '^net.ipv4.ip_local_port_range = ' /etc/sysctl.conf"
end

template "limits.conf" do
  path "/etc/security/limits.conf"
  source "limits.conf.erb"
  owner "root"
  group "root"
  mode  0644
  variables ({
               :soft => node[:fluentd][:soft],
               :hard => node[:fluentd][:hard]
             })
end

execute "adding-gpg-td" do
  command "curl -L http://packages.treasure-data.com/debian/RPM-GPG-KEY-td-agent | apt-key add -"
  not_if "apt-key list | egrep -q 'Treasure Data'"
end

template "treasure-data.list" do
  path "/etc/apt/sources.list.d/treasure-data.list"
  owner "root"
  group "root"
  mode  0644
  notifies :run, 'execute[apt-get-update]', :immediately
end

dpkg_package "libssl0.9.8" do
        source "#{Chef::Config[:file_cache_path]}/#{node[:fluentd][:libssl_file]}"
        action :nothing
end

remote_file "#{Chef::Config[:file_cache_path]}/#{node[:fluentd][:libssl_file]}" do
        source node[:fluentd][:libssl_url]
        not_if "dpkg -l | egrep -q 'libssl0.9.8'"
        mode 0644
        notifies :install, 'dpkg_package[libssl0.9.8]', :immediately
end
```

```ruby:site-cookbook/recipes/server.rb
include_recipe "fluentd"

package "td-agent" do
  action :install
end

service "td-agent" do
  action [ :enable, :start ]
  supports :status => true, :restart => true
end
```

##server.rb ?
`server.rb` をあえて作っていますけれども、全く同じファイルの内容で、`client.rb` もあります。
client 側と、server 側とで、`fluentd` の構成が変わるだろうなーと、`template` の差異が発生すると見込んでわけて作ってみました。

なので、使い方としては、`xxx.json` で `recipe[fluentd::server]` として呼んであげると、`server.rb`内で `include_recipe` しているという流れです。なので、[fluentd::client]と[fluentd::server]は同時に使うことはないです。

お気に召したら、どうぞ。