Fluentdはデータ収集ソフトウェア最強のツールである

6 min read読了の目安(約5500字

はじめに

最近Fluentdを使い始め、あまりの使い心地の良さに「ああ、最高だ」という気持ちになったため、素晴らしさを共有すべくこの記事を執筆することに致しました。一からFluentdを自分でやろうとすると中々手が出なかったり、「完全に理解した」という状態になるまで二日くらい掛かったりするので、それがこの記事を10分程度読むだけで200倍くらいの時間圧縮に繋がれば良いなと思います。少なくとも自分だけで一から学ぼうとするよりはるかに効率が良いと考えております。

Fluentdは高信頼性のデータ収集ソフトウェア

Fluentdはオープンソースのデータ収集ソフトウェアで、多機能で、高速かつ信頼性高くデータ転送を行ってくれます。なぜ信頼性が高いのかというと、データ転送時に一時的にバッファーに情報を蓄積出来る機構を持っているため、障害が発生してもログの再送制御を行い欠損を防ぐことが出来るからなんですね。しかも驚くことに、欲しい機能がほぼほぼ網羅されていたので「いやぁ、これは凄いなぁ」と思いました(logrotateとかファイルローテートするタイミングでログが重複したり欠損したりするのではないかと考えていたのですがちゃんとそういう問題も考慮されていたようで「ここまでやってくれるのか!!!〜」とその時は物凄く感動しました)

ログはそもそも重要なのか

ある程度エンジニアとして経験を積んだ方であればログの重要性を理解しているとは思いますが、念のため説明すると、保守性の観点から、ただログを適当に出力するのではなく、ログの可読性、追跡可能性、完全性等確保されたログはMTTR(平均修復時間)を短く出来ます。また、調査の時に使用するだけでなく上場企業であればログは監査証跡という意味でも非常に重要な役割を持っています。さらに、問い合わせ対応をする際にもログは重要で、このログに欠損があると一大事です。決済処理でエラーが発生していたとして、さらにログに欠損が生じていたことが分かり「これ以上情報を収集することができませんでした」では企業としての信頼、信用が失われかねないです。たかがログ、されどログです。

使い方を「完全に理解」する

先ずはやってみると感覚が掴めるでしょう。環境はmacOS前提で説明します。コードは基本コピー&ペーストで大丈夫であるように記事を書いているつもりではありますが、もしも動作しなかったなどの場合は、すみません。ちなみに本記事では、説明を細かく入れ過ぎると返って伝わりにくくなり、読み手の負担になるという理由から単純さのため皆さんを信じて基本「設定ファイルを眺めていればなんとなく概要は理解してくれるであろう」という前提で説明します。

環境構築

# FluentdのDockerイメージを引っ張ってきます。
# https://docs.fluentd.org/container-deployment/install-by-docker
$ docker pull fluent/fluentd:edge-debian
# UbuntuのDockerイメージも引っ張ってきます(実験で使用するので)
$ docker pull ubuntu:16.04

curl -> コンテナログ出力

Fluentd設定ファイル(http.conf)

# in
<source>
  @type http
  port 9880
  bind 0.0.0.0
</source>

# out
<match **>
  @type stdout
</match>

説明

<source>は「ログをhttp経由で9880番ポートで待ち受ける」ということを意味しています。
<match>は「どこにログを出力するか」の指定で「標準出力(この場合コンテナログに出す)」になります。

この設定ファイルをFluentdに読み込ませ「curl -> httpエンドポイント -> コンテナログ出力」という流れでログを送ります。

手順

  1. Fluentdを立ち上げます。
$ docker run -d --rm --name=http_fluentd -p 9880:9880 -v `pwd`/http.conf:/fluentd/etc/http.conf fluent/fluentd:edge-debian -c /fluentd/etc/http.conf

$ docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                         NAMES
7dbb509d35ac        fluent/fluentd:edge-debian   "tini -- /bin/entryp…"   3 minutes ago       Up 3 minutes        5140/tcp, 24224/tcp, 0.0.0.0:9880->9880/tcp   http_fluentd
  1. curlでログを送ります。
$ curl -X POST -d 'json={"json":"message"}' http://127.0.0.1:9880/sample.test
  1. コンテナログに以下がログが表示されていることを確認
2021-03-28 16:00:44.025672400 +0000 sample.test: {"json":"message"}

以上、このような流れでログを送ることが出来ます。今回はhttpエンドポイントを開き、そこに対しcurlでログを送信するというものでしたが、他にもtailを使うものや、Fluentd -> Fluentdでログを送ることも可能です。

tail -> Fluentd(送信側) -> Fluentd(受信側) -> File保存

送信側の<match>@typeforward、受信側の<source>@typeforwardに指定すると「Fluentd -> Fluentd」というようにログを送ることが出来ます。基本先ほどと同じ要領ですが、今度は送信側と受信側で二つ設定ファイルを用意します。

送信側Fluentd設定ファイル(sender_tail_file.conf)

# in
<source>
    @type tail
    path /tmp/log/sender_tail_file.log
    pos_file /tmp/log/sender_tail_file.log.pos
    tag something.tag
    <parse>
        @type none
    </parse>
</source>

# out
<match something.tag>
    @type forward
    flush_interval 3

    <server>
        host rec_tail_file_fluentd
        port 24224
    </server>
</match>
ディレクティブ 説明
@type tailでin_tailプラグインを使ってファイルを読み込みます
path tailする対象ログファイル
pos_file ざっくりいうと読み込む位置。
Fluentd再起動した場合はここをもとに読み込み開始をする。
tag tailで読み込んだログにこのtagが付与される

受信側Fluentd設定ファイル(receiver_tail_file.conf)

# in
<source>
    @type forward
    port 24224
</source>

# out
<match something.tag>
    @type file
    append true
    flush_interval 3
    path /tmp/log/receiver_tail_file
</match>

# 流れてきたログのtagが何もマッチしなかったらここで処理される
<match **>
    @type file
    append true
    flush_interval 3
    path /tmp/log/receiver_tail_file_other
</match>

手順

  1. 以下のコマンドを叩く
$ mkdir -p tmp/etc && mkdir -p tmp/log

$ touch tmp/log/sender_tail_file.log
  1. 設定ファイルを置く(上記設定ファイルをここにコピペしてください)
# 送信側
$ vim tmp/etc/sender_tail_file.conf

# 受信側
$ vim tmp/etc/receiver_tail_file.conf
  1. 受信側、送信側Fluentdコンテナ立ち上げる
# 受信側立ち上げ(リンクの関係上受信側から立ち上げる)
$ docker run --rm -d --name=rec_tail_file_fluentd --expose 24224 -v `pwd`/tmp/etc:/fluentd/etc -v `pwd`/tmp/log:/tmp/log fluent/fluentd:edge-debian -c /fluentd/etc/receiver_tail_file.conf

# 送信側
$ docker run --rm -d --name=sender_tail_file_fluentd --link rec_tail_file_fluentd -v `pwd`/tmp/etc:/fluentd/etc -v `pwd`/tmp/log:/tmp/log fluent/fluentd:edge-debian -c /fluentd/etc/sender_tail_file.conf
  1. echoでtestという文字列を書き込む
$ echo "test" >> tmp/log/sender_tail_file.log
  1. 無事保存までされたか確認(receiver_tail_file.YYYYMMDD.log)
$ cat tmp/log/receiver_tail_file.20210411.log
2021-04-11T15:53:45+00:00	something.tag	{"message":"test"}

後はどのような挙動になるか色々実験してみると理解がより深まると思うので是非試して見てください。

最後に

Fluentd、便利ですよね。実際に使用するときはECSのTask DefinitionでFluentdをデーモンコンテナとしてたて、アプリケーションコンテナのlog-driverにfluentdを指定することで、コンテナで標準出力された際にFluentdへログが流れ込む形になるかと思います(その時の送信側Fluentd設定ファイルの<source>@typeforwardを指定します)。そうしてログを他サーバーやS3等に対して集約したら実際に調査や分析する際にログをそこで見ていくことになるかと思います。ログの集約をしていないと、サーバーが何十台もあるという場合に毎回それぞれのサーバーにアクセスしてログを見にいくことになるので時間が掛かってしまいます。そうならないためにもFluentdでささっと構築してログを集約させるようにしましょう。

では、今日はこれまでと致します。
長くなりましたが、読んでいただきありがとうございました。

参考文献