仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

Fluentdを触ってみた(Fluentd Quickstart)

Fluentdとは

Fluentdについて調べると、様々なデータの収集を統一できるオープンソースのデータコレクターといったような説明が出てきます。イベントログ、アプリケーションログ、click streamの分析に使用できるツールとの説明も見つかります。

click streamとはWebサイトの閲覧者が訪問してからそのサイトから離脱するまでの間にどのコンテンツをどのような順序で遷移したかを記録したデータのことを指します。

Fluentd Architecture (公式サイトより引用)

さまざまな形式のログをFluentdで処理して、Fluentdに対応するソフトウェアと連携することで監視ソフトウェアを使ったアラートのソースとして使ったり、MongoDB, MySQL, Hadoopなどにデータを投入してさまざまな解析に使ったり、Amazon S3と連携させて、必要なデータをアーカイブするといったことが可能になります。

Fluentdとディストリビューション

FluentdはLinuxのほか、WindowsやmacOSにもインストールすることができます。今回はCentOS 7にインストールしてみます。Linux版についてはSupport Platforms にもまとめられていますが、RHELの5から8までの対応のほか、Amazon Linux 2、Ubuntu Focal(20.04LTS)、Debian Buster (9)まで対応のパッケージが用意されているようです。FluentdはRubyで書かれており、RubyGem を使えばリストアップされていないLinuxディストリビューションやそのバージョンでも動作するようです。

パッケージを使ったインストールの場合はtd-agentとcalyptia-fluentdという二つのパッケージが用意されています。

FluentdはほとんどのコードはRubyで作成されており、パフォーマンスが重要な部分は C で作成されています。ただし、一部のユーザーは、Rubyのインストールとモジュール追加のためのRubyツールの操作が困難な場合があります。それらを簡単に導入できるようにパッケージングしたものがtd-agentやcalyptia-fluentdになります。

「td-agent」はTreasure Data, Incが開発、提供しているFluentdです。「calyptia-fluentd」はCalyptia, Incが開発、提供しているFluentdです。td-agentと比べるとcalyptia-fluentdは新しいバージョンのRubyを利用していたり、CentOS Stream 8をサポートしているなどといった特徴がある以外はtd-agentと同様、Fluentdの安定版として利用可能です。Rubyのバージョン、バイナリーやライブラリー、設定ファイルのパスが違う他は同様に利用可能です。

Fluentdのインストール

[追記] 以下、td-agent v3をセットアップしていますが、td-agent v4 (td-agent 4.4.1 fluentd 1.15.2)でも同じ設定で動作することを確認しています。


Fluentdのインストール を開きます。今回はCentOS 7にインストールするので、 Install by RPM Package (Red Hat Linux) に従ってインストールします。

ドキュメントにはtd-agentとcalyptia-fluentdの導入手順が併記されていますので、今回はtd-agentをインストールします。

インストールはシェルスクリプトが用意されていますので、これをcurlコマンドとshコマンドを使って実行するだけで、リポジトリーの設定からインストールまで自動で行えます。td-agent 4とtd-agent 3のいずれかを選べるようになっていますが、td-agent v2 vs v3 vs v4 をもとに、OSに対して適切なバージョンを選んでください。当然ながらv4の方が新しいバージョンにあっていますが、v3を選んでもFluentdのバージョンは1なので、同じようなコンフィグレーションの書き方でFluentdの動作を定義できるようです。

本例ではtd-agentのv3をインストールしました。リポジトリーの追加、td-agentパッケージのインストールが自動で行われます。

# td-agent 3
$ curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent3.sh | sh

$ td-agent --version
td-agent 1.11.5
$ /opt/td-agent/embedded/bin/fluentd --version
fluentd 1.11.5

下のfluentdのパスはps aux|grep td-agentとかで確認しました。 その結果、今回インストールされたtd-agent(Fluentd)のバージョンは1.11.5とのことです。

td-agentのスクリプトはここ をクリックすることで閲覧できます。インストールの前にyum check-updateを実行している意味は謎ですが、どういったことを行なっているかはスクリプトを見ればすぐ理解できると思います。

ここでちょっと話は脱線しますが、Fluentdのドキュメントサイトは本文のコピペがブラウザーによってうまく動作しませんので注意してください。コマンド部分はマウスの矢印をそのボックス内に移動すると、右上に「コピー」するためのボタンが現れますので、それを使うことでコマンドをコピーできます。うっかりそのまま実行するとtd-agent 4とtd-agent 3のスクリプトが投入されてしまうので、エディターに貼り付けて必要な方だけを投入しましょう。

DebianやUbuntuと異なり、Red Hat Enterprise Linux(以下RHEL)やCentOS Linuxを含むRHELクローンは、インストール後にサービスの起動が必要になります。次のように実行しておきます。これで、初回起動とシステム起動時に自動でサービスを起動する設定がなされます。

$ sudo systemctl enable --now td-agent

インストール後は公式ドキュメントのように次のように実行すると、Fluentdのログに入力したデータがそのまま出力されているのがわかります。

$ curl -X POST -d 'json={"json":"message"}' http://localhost:8888/debug.test
$ tail -n 1 /var/log/td-agent/td-agent.log
2018-01-01 17:51:47 -0700 debug.test: {"json":"message"}

これはtd-agentのデフォルト設定で、次のような設定が書かれているためのようです。入力プラグインとしてはhttpを使っているようです。

<match td.*.*>
  @type tdlog
  @id output_td
  apikey YOUR_API_KEY

  auto_create_table
  <buffer>
    @type file
    path /var/log/td-agent/buffer/td
  </buffer>
...
</match>
...
<source>
  @type http
  @id input_http
  port 8888
</source>

Fluentdの設定

Fluentdはインストールしただけでは当然ながら動きません。Fluentdの設定が必要です。 Fluentdの基本はインプットとアウトプットの定義です(そのほか、ログから適切なデータを取り出して整形するためのFilter PluginやParser Plugin, Formatter Pluginなどがありますが、今回はそこは詳しくは触れません。詳細は Fluentd Docs をご覧ください)。インプットは何をターゲットのするかを示し、アウトプットは何に対してデータを出力するかを示します。

Fluentdのインプット対象についてはInput Plugins に、アウトプット対象はOutput Plugins にまとめられています。

設定の前に

今回Fluentdの動作を確認するために、Apache Web Serverをインストールしてみます。CentOSの場合はhttpdというパッケージをインストールします。インストール後はApache Web Serverを起動しておきましょう。

$ sudo yum install httpd
$ sudo systemctl enable --now httpd

ポートも解放しておきます。今回はhttpのみ利用するので、ポートかサービスいずれかの方法で必要なポートを解放してください。

sudo firewall-cmd --permanent --add-port=80/tcp

or

sudo firewall-cmd --permanent --add-service=http

&

sudo firewall-cmd --reload

td-agentのデフォルト設定は、ユーザーとグループはtd-agentが設定されています。なんとなく想像がつくと思いますが、デフォルトの設定だと多くのディレクトリーに書き込む権限がないため、ログの収集がうまくいかないことがあります。以下のようにユーザー、グループをrootに設定することで回避できます。

$ sudo vi /usr/lib/systemd/system/td-agent.service
[Service]
User=root
Group=root
...
$ sudo systemctl daemon-reload
$ sudo systemctl restart td-agent.service

インプットの定義

Input Pluginsではtail、forward、http、syslogなどがよく使われるようです。 今回は次のような設定を試してみましょう。

今回はtailを使っています。なんとなく指定しているパスから感づくと思いますが、Apache Web Serverのログをインプットとして定義しているのがわかると思います。

重要なのはtagという部分です。Fluentdはこのタグを一つのジョブの一連の流れと認識するので、「どこからデータをインプットして、整形して、どこに対してデータを出力する」という設定を定義するときに共通のタグをそれぞれ設定します。

ちなみにtd-agentは/etc/td-agent/td-agent.confが設定ファイルです。

<source>
  @type tail
  path /var/log/httpd/access_log
  pos_file /var/log/td-agent/access_log.pos
  format apache2
  tag apache.access.test
</source>

アウトプットの定義

同じマシン上の設定ファイルに次のような設定をすることで「アウトプットの定義」が可能になります。アウトプットプラグインとしてfileを使っているので、入力してデータをその下で定義している時間の間隔でデータを書き込んでいきます。

<match apache.access.test>
  @type file
  path /tmp/output_access_log
  timekey 60m
  timekey_wait 1m
  chunk_limit_size 256m
</match>

設定を書き込んだ後、Fluentdのサービスを再起動します。

$ sudo systemctl restart td-agent

その上でそのサーバーにWebブラウザーやcurlコマンドなどでアクセスしてみましょう。すると指定したディレクトリーにログが溜まっていくのが確認できます。

]# ls /tmp/output_access_log
buffer.b5eb7266f1647cf0e74c072bb9127a852.log  buffer.b5eb7266f1647cf0e74c072bb9127a852.log.meta

]# tail /tmp/output_access_log/buffer.b5eb7266f1647cf0e74c072bb9127a852.log

2022-10-20T07:37:49+00:00       apache.access.test      {"host":"192.168.222.12","user":null,"method":"GET","path":"/","code":403,"size":4897,"referer":null,"agent":"curl/7.29.0"}
2022-10-20T07:50:14+00:00       apache.access.test      {"host":"192.168.222.12","user":null,"method":"GET","path":"/","code":403,"size":4897,"referer":null,"agent":"curl/7.29.0"}
2022-10-20T07:52:10+00:00       apache.access.test      {"host":"172.16.214.194","user":null,"method":"GET","path":"/","code":403,"size":4897,"referer":null,"agent":"curl/7.29.0"}

Fluentdとして最低限の動作はこれで確認できました。

コラム

Fluentdの使い方について知るには、まずドキュメントを見るのがするべきことですが、理解を深めるためにいろいろなサイトを見て設定方法を確認することもあると思います。 しかし、Fluentdは設定の書き方が初期の実装の頃と比べてだいぶ変わっているため、古い情報をそのまま設定に落とし込んでもうまく動かない場合があります。

例えば次のような設定の例では、typeの前に@がついていない場合の設定例は古いバージョンのFluentd向けの設定です。そのほかにも中の設定の書き方がバージョンによって変わっている場合があるのでWebの情報を参考にする場合はどのバージョンのFluentdをターゲットにしているのかをよく確認すると良いです。どうやって動かすのかさっぱりわからなかった時は色々試行錯誤するのが大変でした。ちなみに下に貼り付けた設定はtd-agentのデフォルト設定に書かれていた記述例です。本例では古い設定を使って記述していましたが、本来は「parse」タグででフォーマット形式を囲むのが今風の書き方のようですね。

#<source>
#  @type tail
#  @id input_tail
#  <parse>
#    @type apache2
#  </parse>
#  path /var/log/httpd-access.log
#  tag td.apache.access
#</source>

現在インストールしたバージョンではいずれの記述方法でも動作するようですが、新しいバージョンがリリースされたときに設定が通らない可能性もあるので、基本は公式のドキュメントのプラグインの設定のページをまず確認することが重要でありそうです。

Fluentdをお試し

Fluentdと対象のアプリケーションサーバーが同じサーバー上で動いており、アプリケーションサーバーのログを同じマシン上のFluentdが別のファイルにログを書くだけでは面白くありませんので、今度はアプリケーションサーバーとログ集約サーバーみたいな構成を作ってお試ししてみようと思います。

本例をためするには、次の環境が必要になりますので、事前に用意してください。

  • マシン2つ(物理マシンでも仮想マシンでも可)
  • マシン間がネットワークでつながっていること
  • 双方、インターネットアクセスができること

また以下のポートを使って通信するため、2つのマシンでポートを解放する必要があります。

  • 24224/tcp, 24224/udp (Fluentdのデフォルトポート)
  • 30000/tcp, 30000/udp (マシン間forwardで利用)
  • 8888/tcp (td-agentの初期設定で利用)

8888ポートはlsof -i:8888などでみたところTCPポートしか利用していなかったことから、8888/tcpポートだけを解放すれば良いようです。

今回の例はOpenStackインスタンス上で環境を用意したためポート解放はセキュリティグループを使って行いましたが、手元の環境で用意する場合はRHELやCentOSであればfirewall-cmdを使ってポート解放すれば良いでしょう。

sudo firewall-cmd --permanent --add-port=24224/tcp
sudo firewall-cmd --permanent --add-port=24224/udp
sudo firewall-cmd --permanent --add-port=30000/tcp
sudo firewall-cmd --permanent --add-port=30000/udp
sudo firewall-cmd --permanent --add-port=8888/tcp
sudo firewall-cmd --reload

Apache2とFluentd(データの送信側)は次のような設定をFluentdに仕込んでおきます。fowardプラグインについてはforward にまとめられていますが、今回はどのようなデータ(本例ではApache Web Serverのアクセスログ)をどのノード(本例ではポート30000で待ち受けしている192.168.222.44というIPアドレスのノード)に対してデータを送り出す設定をしています。

ちょっとパスを書き換えれば、Webサーバーのエラーログも収集できます。

# in
<source>
  @type tail
  path /var/log/httpd/access_log
  pos_file /var/log/td-agent/access_log.pos
  format apache2
  tag apache.access.test
</source>

# out
<match apache.access.test>
#  @type file
#  path /tmp/output_access_log
#  timekey 60m
#  timekey_wait 1m
#  chunk_limit_size 256m
  @type forward
  flush_interval 3
     <server>
        host 192.168.222.44
        port 30000
    </server>
</match>

ログ収集サーバー(データの受け取り側)のFluentdに次のような設定を行います。ノードの入力元として「192.168.222.44 ポート30000」を指定しています。このIPアドレスは自らのIPアドレスです。

アウトプットには二つの設定が仕込まれています。上はタグがマッチする場合、下の設定はタグがマッチしない場合です。本例ではアクセスログは上で指定したディレクトリー内に、マッチしない他のログ(例えばFluentdのログなど)は下のディレクトリーに保管されます。

# in
<source>
    @type forward
    port 30000
    bind 192.168.222.44
</source>

# out
<match apache.access.test>
    @type file
    append true
    flush_interval 3
    path /tmp/log/receiver_tail_file
</match>
# out_non_match_tag
<match **>
    @type file
    append true
    flush_interval 3
    path /tmp/log/receiver_tail_file_other
</match>

設定を書き込んだ後、それぞれのノードのFluentdのサービスを再起動します。

$ sudo systemctl restart td-agent

どちらのログも/tmpディレクトリーにデータを書き込んでいますので、必要に応じてデータを永続化できるマウントポイント上のディレクトリーをパスとして指定すればログを永続化できますし、Outputプラグインのs3 を使えば、Amazon S3にデータを保管できます。MongoDB も利用できます。

これにより、Apache Web Serverが動いているマシン上のWebサーバーにアクセスすると、ログ集約サーバー側のFluentdが指定したパスにアクセスログを保管するように動きます。

match apache.access.testにマッチしたログの例

条件にマッチした方のログは、Web Serverのアクセスログが表示されました。同じ時間で重複したログが出ているのはブラウザーの機能(先読み機能など)によるものです。

]# cat /tmp/log/receiver_tail_file.20221021.log 
2022-10-21T07:53:37+00:00   apache.access.test  {"host":"172.16.1.14","user":null,"method":"GET","path":"/noindex/css/fonts/Light/OpenSans-Light.woff","code":404,"size":241,"referer":"http://172.16.214.194/noindex/css/open-sans.css","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0"}
2022-10-21T07:53:37+00:00   apache.access.test  {"host":"172.16.1.14","user":null,"method":"GET","path":"/noindex/css/fonts/Bold/OpenSans-Bold.woff","code":404,"size":239,"referer":"http://172.16.214.194/noindex/css/open-sans.css","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0"}
2022-10-21T07:53:38+00:00   apache.access.test  {"host":"172.16.1.14","user":null,"method":"GET","path":"/noindex/css/fonts/Light/OpenSans-Light.ttf","code":404,"size":240,"referer":"http://172.16.214.194/noindex/css/open-sans.css","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0"}
2022-10-21T07:53:38+00:00   apache.access.test  {"host":"172.16.1.14","user":null,"method":"GET","path":"/noindex/css/fonts/Bold/OpenSans-Bold.ttf","code":404,"size":238,"referer":"http://172.16.214.194/noindex/css/open-sans.css","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0"}
2022-10-21T08:11:26+00:00   apache.access.test  {"host":"172.16.1.14","user":null,"method":"GET","path":"/","code":403,"size":4897,"referer":null,"agent":"curl/7.79.1"}

同上にマッチしなかったログの例

マッチしなかった方のログには、主にFluentdサービスが動いているか、待ち受けしているかなどのログが出力されました。

# cat /tmp/log/receiver_tail_file_other.20221021.log 
2022-10-21T07:17:46+00:00   fluent.info {"pid":8082,"ppid":27307,"worker":0,"message":"starting fluentd worker pid=8082 ppid=27307 worker=0"}
2022-10-21T07:17:46+00:00   fluent.info {"port":24223,"bind":"0.0.0.0","message":"listening port port=24223 bind=\"0.0.0.0\""}
2022-10-21T07:17:46+00:00   fluent.info {"uri":"druby://127.0.0.1:24230","object":"Fluent::Engine","worker":0,"message":"[input_debug_agent] listening dRuby uri=\"druby://127.0.0.1:24230\" object=\"Fluent::Engine\" worker=0"}
2022-10-21T07:17:46+00:00   fluent.info {"port":24224,"bind":"0.0.0.0","message":"[input_forward] listening port port=24224 bind=\"0.0.0.0\""}
2022-10-21T07:17:46+00:00   fluent.info {"worker":0,"message":"fluentd worker is now running worker=0"}
2022-10-21T07:17:49+00:00   fluent.info {"worker":0,"message":"fluentd worker is now stopping worker=0"}
2022-10-21T07:17:51+00:00   fluent.info {"pid":8139,"ppid":8134,"worker":0,"message":"starting fluentd worker pid=8139 ppid=8134 worker=0"}
2022-10-21T07:17:51+00:00   fluent.info {"port":24223,"bind":"0.0.0.0","message":"listening port port=24223 bind=\"0.0.0.0\""}
2022-10-21T07:17:51+00:00   fluent.info {"uri":"druby://127.0.0.1:24230","object":"Fluent::Engine","worker":0,"message":"[input_debug_agent] listening dRuby uri=\"druby://127.0.0.1:24230\" object=\"Fluent::Engine\" worker=0"}
2022-10-21T07:17:51+00:00   fluent.info {"port":24224,"bind":"0.0.0.0","message":"[input_forward] listening port port=24224 bind=\"0.0.0.0\""}
2022-10-21T07:17:51+00:00   fluent.info {"worker":0,"message":"fluentd worker is now running worker=0"}
2022-10-21T07:18:45+00:00   fluent.info {"worker":0,"message":"fluentd worker is now stopping worker=0"}
2022-10-21T07:22:18+00:00   fluent.info {"pid":12995,"ppid":10753,"worker":0,"message":"starting fluentd worker pid=12995 ppid=10753 worker=0"}
2022-10-21T07:22:18+00:00   fluent.info {"port":30000,"bind":"192.168.222.44","message":"listening port port=30000 bind=\"192.168.222.44\""}
2022-10-21T07:22:18+00:00   fluent.info {"uri":"druby://127.0.0.1:24230","object":"Fluent::Engine","worker":0,"message":"[input_debug_agent] listening dRuby uri=\"druby://127.0.0.1:24230\" object=\"Fluent::Engine\" worker=0"}
2022-10-21T07:22:18+00:00   fluent.info {"port":24224,"bind":"0.0.0.0","message":"[input_forward] listening port port=24224 bind=\"0.0.0.0\""}
2022-10-21T07:22:18+00:00   fluent.info {"worker":0,"message":"fluentd worker is now running worker=0"}
2022-10-21T07:22:20+00:00   fluent.info {"worker":0,"message":"fluentd worker is now stopping worker=0"}
2022-10-21T07:22:22+00:00   fluent.info {"pid":13052,"ppid":13047,"worker":0,"message":"starting fluentd worker pid=13052 ppid=13047 worker=0"}
2022-10-21T07:22:22+00:00   fluent.info {"port":30000,"bind":"192.168.222.44","message":"listening port port=30000 bind=\"192.168.222.44\""}
2022-10-21T07:22:22+00:00   fluent.info {"uri":"druby://127.0.0.1:24230","object":"Fluent::Engine","worker":0,"message":"[input_debug_agent] listening dRuby uri=\"druby://127.0.0.1:24230\" object=\"Fluent::Engine\" worker=0"}
2022-10-21T07:22:22+00:00   fluent.info {"port":24224,"bind":"0.0.0.0","message":"[input_forward] listening port port=24224 bind=\"0.0.0.0\""}
2022-10-21T07:22:22+00:00   fluent.info {"worker":0,"message":"fluentd worker is now running worker=0"}

とりあえず基本っぽいFluentdの環境は作れましたので、あとはやりたいことに合わせて設定を変更していくだけです。

[追記1] ドキュメントには載っていないものを含むFluentd Pluginの一覧はこちらにまとまっているようです。

www.fluentd.org

[追記2] ガイドはこちらにありました。ログをMongoDBに投入する方法とか、ログをS3に放り込む方法などが設定込みで載っているようです。

www.fluentd.org