CLOVER🍀

That was when it all began.

Ubuntu Linux 18.04 LTSに、Fluent Bitをインストールする

これは、なにをしたくて書いたもの?

以前、少しFluentdを触っていたのですが、Fluent Bitも1度確認しておいた方がいいかな、と思いまして。

今回、軽く試してみることにしました。

Fluent Bit?

Fluent Bitのオフィシャルサイトは、こちら。

Fluent Bit

GitHubリポジトリは、こちら。

GitHub - fluent/fluent-bit: Fast and Lightweight Log processor and forwarder for Linux, BSD and OSX

Fluent Bitとは、オープンソースかつ、マルチプラットフォームで動作するログプロセッシングツールです。

様々なデータソース、様々なデータフォーマットを扱うことができ、データの保証やルーティングを行いつつ、複数の
出力先にデータを渡すことができます。

What is Fluent Bit ? - Fluent Bit: Official Manual

A Brief History of Fluent Bit - Fluent Bit: Official Manual

これらの特徴を、低リソースで行えるところがポイントです。

Fluentdと、Fluent Bitの違いは以下のページに書かれています。

Fluentd & Fluent Bit - Fluent Bit: Official Manual

Fluentd Fluent Bit
対象とする環境 コンテナ/サーバー 組み込みLinux/コンテナ/サーバー
実装言語 CおよびRuby C
メモリ 〜40MB 〜650KB
パフォーマンス ハイパフォーマンス ハイパフォーマンス
依存関係 いくつかのRuby Gem 依存なし
プラグイン 1,000以上のプラグインが利用可能 70ほどのプラグインが利用可能
ライセンス Apache License 2.0 Apache License 2.0

Fluentdに比べ、より軽量なプロダクトだと言えそうです。その代わり、利用可能なプラグイン数はだいぶ減ることになりますね。

キーコンセプトは、以下のドキュメントに書かれているので見ておくとよいでしょう。

Key Concepts - Fluent Bit: Official Manual

Buffering - Fluent Bit: Official Manual

Data Pipeline - Fluent Bit: Official Manual

Fluentdと同じように、ログをレコードとして扱ってタグを振ったり、バッファリングの仕組み、Input、Filter、Outputなどの
パイプラインを組み上げることができます。

説明はこのあたりにして、使っていってみましょう。

環境

今回の環境は、こちらです。Ubuntu Linux 18.04 LTS。

$ uname -srvmpio
Linux 4.15.0-96-generic #97-Ubuntu SMP Wed Apr 1 03:25:46 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:    18.04
Codename:   bionic

Fluent Bitをインストールする

では、Fluent Bitをインストールします。サポートされているプラットフォームを確認。

Supported Platforms - Fluent Bit: Official Manual

Linux、Windowsが大丈夫ですね。

Ubuntu Linuxの場合、aptリポジトリがあるので、こちらを使います。

Ubuntu - Fluent Bit: Official Manual

GPG鍵のインポート。

$ wget -qO - https://packages.fluentbit.io/fluentbit.key | sudo apt-key add -

リポジトリの追加。

$ sudo sh -c 'echo "deb https://packages.fluentbit.io/ubuntu/bionic bionic main" >> /etc/apt/sources.list'

更新。

$ sudo apt update

「td-agent-bit」をインストールします。

$ sudo apt install td-agent-bit

バージョンを確認。

$ /opt/td-agent-bit/bin/td-agent-bit --version
Fluent Bit v1.4.2

この時点では、systemd上はまだ有効になっていません。

$ sudo systemctl status td-agent-bit
● td-agent-bit.service - TD Agent Bit
   Loaded: loaded (/lib/systemd/system/td-agent-bit.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

設定ファイルは、こちら。

$ ls -l /etc/td-agent-bit
total 16
-rw-r--r-- 1 root root 4659 Apr  2 00:58 parsers.conf
-rw-r--r-- 1 root root   45 Apr  2 00:58 plugins.conf
-rw-r--r-- 1 root root 1002 Apr  2 00:58 td-agent-bit.conf

デフォルトの設定ファイルの内容を、確認してみましょう。設定ファイルに関するドキュメントは、こちら。

Configuring Fluent Bit - Fluent Bit: Official Manual

Configuration File - Fluent Bit: Official Manual

まずは、本体の設定ファイル。

$ grep -v '#' /etc/td-agent-bit/td-agent-bit.conf 
[SERVICE]
    Flush        5

    Daemon       Off

    Log_Level    info

    Parsers_File parsers.conf
    Plugins_File plugins.conf

    HTTP_Server  Off
    HTTP_Listen  0.0.0.0
    HTTP_Port    2020

[INPUT]
    Name cpu
    Tag  cpu.local
    Interval_Sec 1

[OUTPUT]
    Name  stdout
    Match *

Parserの定義。
/etc/td-agent-bit/parsers.conf

[PARSER]
    Name   apache
    Format regex
    Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z

[PARSER]
    Name   apache2
    Format regex
    Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>.*)")?$
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z

[PARSER]
    Name   apache_error
    Format regex
    Regex  ^\[[^ ]* (?<time>[^\]]*)\] \[(?<level>[^\]]*)\](?: \[pid (?<pid>[^\]]*)\])?( \[client (?<client>[^\]]*)\])? (?<message>.*)$

[PARSER]
    Name   nginx
    Format regex
    Regex ^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z

[PARSER]
    # https://rubular.com/r/IhIbCAIs7ImOkc
    Name        k8s-nginx-ingress
    Format      regex
    Regex       ^(?<host>[^ ]*) - (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*) "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" (?<request_length>[^ ]*) (?<request_time>[^ ]*) \[(?<proxy_upstream_name>[^ ]*)\] (\[(?<proxy_alternative_upstream_name>[^ ]*)\] )?(?<upstream_addr>[^ ]*) (?<upstream_response_length>[^ ]*) (?<upstream_response_time>[^ ]*) (?<upstream_status>[^ ]*) (?<reg_id>[^ ]*).*$
    Time_Key    time
    Time_Format %d/%b/%Y:%H:%M:%S %z

[PARSER]
    Name   json
    Format json
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z

[PARSER]
    Name         docker
    Format       json
    Time_Key     time
    Time_Format  %Y-%m-%dT%H:%M:%S.%L
    Time_Keep    On
    # --
    # Since Fluent Bit v1.2, if you are parsing Docker logs and using
    # the Kubernetes filter, it's not longer required to decode the
    # 'log' key.
    #
    # Command      |  Decoder | Field | Optional Action
    # =============|==================|=================
    #Decode_Field_As    json     log

[PARSER]
    Name        docker-daemon
    Format      regex
    Regex       time="(?<time>[^ ]*)" level=(?<level>[^ ]*) msg="(?<msg>[^ ].*)"
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S.%L
    Time_Keep   On

[PARSER]
    Name        syslog-rfc5424
    Format      regex
    Regex       ^\<(?<pri>[0-9]{1,5})\>1 (?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|-)) (?<message>.+)$
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S.%L%z
    Time_Keep   On

[PARSER]
    Name        syslog-rfc3164-local
    Format      regex
    Regex       ^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$
    Time_Key    time
    Time_Format %b %d %H:%M:%S
    Time_Keep   On

[PARSER]
    Name        syslog-rfc3164
    Format      regex
    Regex       /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
    Time_Key    time
    Time_Format %b %d %H:%M:%S
    Time_Format %Y-%m-%dT%H:%M:%S.%L
    Time_Keep   On

[PARSER]
    Name    mongodb
    Format  regex
    Regex   ^(?<time>[^ ]*)\s+(?<severity>\w)\s+(?<component>[^ ]+)\s+\[(?<context>[^\]]+)]\s+(?<message>.*?) *(?<ms>(\d+))?(:?ms)?$
    Time_Format %Y-%m-%dT%H:%M:%S.%L
    Time_Keep   On
    Time_Key time

[PARSER]
    # https://rubular.com/r/3fVxCrE5iFiZim
    Name    envoy
    Format  regex
    Regex ^\[(?<start_time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)? (?<protocol>\S+)" (?<code>[^ ]*) (?<response_flags>[^ ]*) (?<bytes_received>[^ ]*) (?<bytes_sent>[^ ]*) (?<duration>[^ ]*) (?<x_envoy_upstream_service_time>[^ ]*) "(?<x_forwarded_for>[^ ]*)" "(?<user_agent>[^\"]*)" "(?<request_id>[^\"]*)" "(?<authority>[^ ]*)" "(?<upstream_host>[^ ]*)"  
    Time_Format %Y-%m-%dT%H:%M:%S.%L%z
    Time_Keep   On
    Time_Key start_time

[PARSER]
    # http://rubular.com/r/tjUt3Awgg4
    Name cri
    Format regex
    Regex ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<message>.*)$
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S.%L%z

[PARSER]
    Name    kube-custom
    Format  regex
    Regex   (?<tag>[^.]+)?\.?(?<pod_name>[a-z0-9](?:[-a-z0-9]*[a-z0-9])?(?:\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace_name>[^_]+)_(?<container_name>.+)-(?<docker_id>[a-z0-9]{64})\.log$

プラグイン。こちらは、空っぽです。
/etc/td-agent-bit/plugins.conf

[PLUGINS]
    # Path /path/to/out_gstdout.so

こちらを変更して、Fluent Bitを簡単に試してみましょう。

TCP Input/Standard Output

最初は、TCPで待ち受けるInputに対して、結果を標準出力してみましょう。

使用するプラグインは、こちら。

TCP - Fluent Bit: Official Manual

Standard Output - Fluent Bit: Official Manual

設定は、このように変更。
/etc/td-agent-bit/td-agent-bit.conf

[SERVICE]
    Flush        5

    Daemon       Off

    Log_Level    info

    Parsers_File parsers.conf
    Plugins_File plugins.conf

    HTTP_Server  Off
    HTTP_Listen  0.0.0.0
    HTTP_Port    2020

[INPUT]
    Name tcp
    Listen 0.0.0.0
    Port 5170
    Format json
    Tag tcp

[OUTPUT]
    Name  stdout
    Match tcp

TCPのリッスンポートは、ドキュメントのサンプルに習って5170とします。

デフォルトで定義してあるInput/Outputの定義は、今回は削除しました。

インストール直後なので、サービスを有効化して起動。

$ sudo systemctl enable td-agent-bit
$ sudo systemctl start td-agent-bit

起動時のログ。Fluent Bit自体のログの設定をしていないので、今回はjournalctlで確認します。

$ sudo journalctl -u td-agent-bit -f

〜省略〜

Apr 24 13:36:56 ubuntu1804.localdomain td-agent-bit[1952]: [2020/04/24 13:36:56] [ info] [input:tcp:tcp.0] listening on 0.0.0.0:5170
Apr 24 13:36:56 ubuntu1804.localdomain td-agent-bit[1952]: [2020/04/24 13:36:56] [ info] [sp] stream processor started

ncコマンドで動作確認。

$ echo '{"message": "Hello Fluent Bit!!"}' | nc localhost 5170

すると、ログにこんな感じで現れます。

Apr 24 13:37:36 ubuntu1804.localdomain td-agent-bit[1952]: [0] tcp: [1587735451.980938391, {"message"=>"Hello Fluent Bit!!"}]

OKそうですね。

Tail Input/Parser Filter/Standard Output

次は、デフォルトで定義されているParserを使って、ApacheのアクセスログファイルをTailで読み込んでみましょう。

利用するプラグインは、こちら。Standard Outputは省略。

Tail - Fluent Bit: Official Manual

Parser - Fluent Bit: Official Manual

とりあえず、Apacheをインストール。

$ sudo apt install apache2

parsers.confに定義されていた、こちらの設定を使います。
/etc/td-agent-bit/parsers.conf

[PARSER]
    Name   apache2
    Format regex
    Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>.*)")?$
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z

Parserの定義をしたファイルを、SERVICEのParsers_Fileで指定することで、Parserの定義を利用できるようですね。

[SERVICE]

    ...

    Parsers_File parsers.conf

Parser - Fluent Bit: Official Manual

で、設定したのがこちら。
/etc/td-agent-bit/td-agent-bit.conf

[SERVICE]
    Flush        5

    Daemon       Off

    Log_Level    info

    Parsers_File parsers.conf
    Plugins_File plugins.conf

    HTTP_Server  Off
    HTTP_Listen  0.0.0.0
    HTTP_Port    2020

[INPUT]
    Name tcp
    Listen 0.0.0.0
    Port 5170
    Format json
    Tag tcp

[INPUT]
    Name tail
    Path /var/log/apache2/access.log
    Db /var/log/td-agent-bit/apache_access_log.db
    Tag apache.access_log

[FILTER]
    Name parser
    Match apache.*
    Key_Name log
    Parser apache2

[OUTPUT]
    Name  stdout
    Match tcp

[OUTPUT]
    Name  stdout
    Match apache.*
    Format json_lines

Apacheログに関する設定を抜き出すと、こんな感じです。

[INPUT]
    Name tail
    Path /var/log/apache2/access.log
    Db /var/log/td-agent-bit/apache_access_log.db
    Tag apache.access_log

[FILTER]
    Name parser
    Match apache.*
    Key_Name log
    Parser apache2

[OUTPUT]
    Name  stdout
    Match apache.*
    Format json_lines

Apacheのアクセスログをどこまで読み込んだかを保存するために、Dbを指定。これを指定しない場合は、Fluent Bitを
再起動するとファイルを最初から読み込んでしまいます。

Dbの実体はSQLite3で、データベースファイルを置くディレクトリは先に作成しておく必要があります。

$ sudo mkdir /var/log/td-agent-bit

タグは、TCPの時と別にしました。また、OutputのFormatはjson_linesにしてあります。

パースする際の「Key_Name」を指定しないといけないのですが、TailのデフォルトのKey名が「log」なようなので、
こちらを指定。

[FILTER]
    Name parser
    Match apache.*
    Key_Name log
    Parser apache2

Tail - Fluent Bit: Official Manual

Fluent Bitを再起動。

$ sudo systemctl restart td-agent-bit

Apacheへアクセス。

$ curl localhost/index.html

Fluent Bit側には、このようにパースされたログが出力されます。

Apr 24 15:25:18 ubuntu1804.localdomain td-agent-bit[3788]: {"date":1587741916.000000,"host":"127.0.0.1","user":"-","method":"GET","path":"/index.html","code":"200","size":"11173","referer":"-","agent":"curl/7.58.0"}

フォーマットは、JSONな感じになっていますね。

TCPの方は、どうだったでしょうか?

$ echo '{"message": "Hello Fluent Bit!!"}' | nc localhost 5170

こちらは、Formatを未指定だったので「msgpack」形式になっています。

Apr 24 15:32:38 ubuntu1804.localdomain td-agent-bit[3788]: [0] tcp: [1587742357.360168161, {"message"=>"Hello Fluent Bit!!"}]

とりあえず、初歩としてはこんなところでしょうか。