CLOVER🍀

That was when it all began.

Fluent BitをDocker logging driverとして使う

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

以前、FluentdをDockerのlogging driverとして使ってみたことがありました。

Docker環境で、コンテナのログをFluentdに出力する(Docker logging driverとして使う) - CLOVER🍀

今回は、Fluent BitをDockerのlogging driverとして使ってみたいと思います。

Fluentd logging driver

Dockerでは、Fluentdをlogging driverとして使うように設定できます。

Fluentd logging driver | Docker Documentation

ここでログの送信先をFluentdではなく、Fluent Bitに変更してみるのが今回やってみることです。

Fluent Bitの記事にも、Dockerコンテナから受け取ったログを、Elasticsearchに送信するサンプルが書かれたりしています。

Fluent Bit - Docker Logging & Elasticsearch

それでは、ちょっと試してみましょう。

環境

今回の環境は、こちら。

$ uname -srvmpio
Linux 4.15.0-99-generic #100-Ubuntu SMP Wed Apr 22 20:32:56 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


$ docker -v
Docker version 19.03.8, build afacb8b7f0


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

Ubuntu Linux 18.04、Fluent Bitは1.4.4を使用します。

お題

今回のお題は、nginxのDockerコンテナに対してFluentd logging driverを設定し、Fluent Bitに送信してみたいと思います。

Fluent BitとDockerは同じホスト(192.168.33.10)で動作させますが、Fluent Bitはネットワーク越しにログを受け取るように
設定します。

Fluent Bitを設定する

では、最初にFluent Bitの設定を行います。

結果は、こんな感じに。

$ 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 forward
    Host 0.0.0.0
    Port 24224

[OUTPUT]
    Name  stdout
    Match *
    Format json_lines

ポイントは、INPUTをfowardにしていることですね。

[INPUT]
    Name forward
    Host 0.0.0.0
    Port 24224

Forward - Fluent Bit: Official Manual

バインドするアドレスは、「0.0.0.0」で設定。

こちらで、Dockerコンテナのログを受け取ります。

結果は、標準出力で確認することにしました。

[OUTPUT]
    Name  stdout
    Match *
    Format json_lines

journalctlで、Fluent Bitのログを確認しておきます。

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

Dockerコンテナを起動する

続いて、Fluent Bitにログを送信するDockerコンテナを起動します。

こんな感じで起動。

$ docker container run \
  -d -p 80:80 --name nginx \
  --log-driver=fluentd \
  --log-opt fluentd-address=tcp://192.168.33.10:24224 \
  --log-opt tag=docker.{{.ImageName}}.{{.Name}}.{{.ID}} \
   nginx:1.17.10

「--log-driver」を「fluentd」とすることで、Fluentd logging driverを利用することができます。

指定しているオプションは、このあたりを参照。

Fluentd logging driver / Options

今回は、Fluent Bitへの送信先を「fluentd-address」で、Fluent Bitで利用するタグを「tag」で指定しました。

タグはこちらのフォーマットで指定しているのですが、今回はFluent Bit側のMatchでタグを見ていないので、あんまり関係が
なかったり…。

Customize log driver output | Docker Documentation

確認する

それでは、確認してみます。

nginxコンテナにアクセス。

$ curl localhost

少し待っていると、Fluent Bit側のログ(というか標準出力)に、こんな感じで出力されれば成功です。

May 17 10:55:25 ubuntu1804.localdomain td-agent-bit[3848]: {"date":1589712924,"container_name":"/nginx","source":"stdout","log":"172.17.0.1 - - [17/May/2020:10:55:24 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.58.0\" \"-\"","container_id":"fa127da978b1895c40d20d851502d42d1bacee5053e9075e4bf6eeca02023379"}

コンテナ名や、コンテナのIDなども要素として含まれます。

ちなみに、この状態だと「docker container logs」コマンドでは、コンテナのログは見れなくなることに注意してください。

$ docker container logs nginx
Error response from daemon: configured logging driver does not support reading

ログをパースしてみる

これだけで終わっても少し物足りない気もするので、ここからさらに、Parserを使ってnginxのログをパースしてみましょう。

Fluent Bitのparsers.confに、nginx向けのParserが定義してあるので、こちらを使います。
/etc/td-agent-bit/parsers.conf

[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

Fluent Bitの設定は、このように変更。

[INPUT]
    Name forward
    Host 0.0.0.0
    Port 24224
    Tag docker.driver.log

[FILTER]
    Name parser
    Match *
    Key_Name log
    Parser nginx
    Preserve_Key Off
    Reserve_Data On
    Tag docker.nginx.log

[OUTPUT]
    Name  stdout
    Match *
    Format json_lines

先ほどの結果として、nginxのログそのものは「log」というキーで出力されているので

May 17 10:55:25 ubuntu1804.localdomain td-agent-bit[3848]: {"date":1589712924,"container_name":"/nginx","source":"stdout","log":"172.17.0.1 - - [17/May/2020:10:55:24 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.58.0\" \"-\"","container_id":"fa127da978b1895c40d20d851502d42d1bacee5053e9075e4bf6eeca02023379"}

Parserの適用先の「Key_Name」を「log」に指定します。Parserで指定するのは、パーサーの名前ですね(今回はnginx)。

[FILTER]
    Name parser
    Match *
    Key_Name log
    Parser nginx
    Preserve_Key Off
    Reserve_Data On
    Tag docker.nginx.log

ここまで設定したらFluent Bitを再起動して、nginxに再度アクセスしてみます。

ログが以下のような感じに分解されて、Fluent Bit側で出力されます。

May 17 12:34:57 ubuntu1804.localdomain td-agent-bit[5033]: {"date":1589718895,"remote":"172.17.0.1","host":"-","user":"-","method":"GET","path":"/","code":"200","size":"612","referer":"-","agent":"curl/7.58.0","source":"stdout","container_id":"7ea3b9cc2b7ac65d2729e722bacbc2b8efc150ec51ccc37405ebf4f313156a42","container_name":"/nginx"}

デフォルトではTime_KeepがOffなのでアクセス時刻はdateフィールドに変換された後に削除されていますが、今回は
これでも良しとしましょう。

また、Parserを使った時に「Reserve_Data」をOnにしておかないと、パースした結果以外のキーは削除されてしまうので注意しましょう。
パース対象となったキー「log」は、今回は残らなくてもいいので「Preserve_Key」をOffにしています(これはデフォルトの挙動)。