docker fluentd logging driver の基礎的な設定

<https://docs.docker.com/engine/admin/logging/fluentd/>

docker container では、コンテナ内の何かしらのプログラムが標準出力 (strout) や標準エラー (stderr) に出力した内容を `docker logs` コマンドで取得することができます。
しかし能動的に取得しいにいくだけでなく、何かしら別の方法で forward をしてくれると助かることもあります。

docker では logging driver という機構で、stdout / stderr に出力された内容を指定された方法で forward する仕組みがあります。

サポートされている logging driver の種類については以下公式ドキュメントを参照ください。

<https://docs.docker.com/engine/admin/logging/overview/#supported-logging-drivers>

# fluentd logging driver
そのうち、この記事では fluentd logging driver についてのみ触れます。

## overview
<https://docs.docker.com/engine/admin/logging/fluentd/>

fluentd logging driver は、上述の logging driver の forward 先として、fluentd の in_forward を送信先に指定することができる logging driver です。

## configuration 
以下、最もシンプルな例を docker compose の設定記述を例に記します。

```
        logging:
            driver: "fluentd"
            options:
                fluentd-address: "localhost:24224"
                tag: "docker.logging_driver.masashi.sada"
```

上記の例では、標準出力の内容を localhost:24224 で起動されている td-agent / fluentd の in_forward port に対して `docker.logging_driver.masashi.sada` というタグで書き込みを行います。

## log sample
こちらは docker container 上で puma を起動した際の例です。

```
20170411T060729+0000    docker.logging_driver.masashi.sada        {"source":"stdout","log":"Puma starting in single mode...","container_id":"a1e6529928d6b06510b2a0ea0bb8813f0e4a5ecf240a2e544da1e9617310f41a","container_name":"/masashi_dev_puma"}
20170411T060729+0000    docker.logging_driver.masashi.sada        {"container_name":"/masashi_dev_puma","source":"stdout","log":"* Version 3.8.0 (ruby 2.3.3-p222), codename: Sassy Salamander","container_id":"a1e6529928d6b06510b2a0ea0bb8813f0e4a5ecf240a2e544da1e9617310f41a"}
20170411T060729+0000    docker.logging_driver.masashi.sada        {"container_name":"/masashi_dev_puma","source":"stdout","log":"* Min threads: 5, max threads: 5","container_id":"a1e6529928d6b06510b2a0ea0bb8813f0e4a5ecf240a2e544da1e9617310f41a"}
20170411T060729+0000    docker.logging_driver.masashi.sada        {"container_id":"a1e6529928d6b06510b2a0ea0bb8813f0e4a5ecf240a2e544da1e9617310f41a","container_name":"/masashi_dev_puma","source":"stdout","log":"* Environment: development"}
20170411T060730+0000    docker.logging_driver.masashi.sada        {"log":"* Listening on tcp://0.0.0.0:3000","container_id":"a1e6529928d6b06510b2a0ea0bb8813f0e4a5ecf240a2e544da1e9617310f41a","container_name":"/masshi_dev_puma","source":"stdout"}
20170411T060730+0000    docker.logging_driver.masashi.sada        {"source":"stdout","log":"Use Ctrl-C to stop","container_id":"a1e6529928d6b06510b2a0ea0bb8813f0e4a5ecf240a2e544da1e9617310f41a","container_name":"/masshi_dev_puma"}
```

| name | description |
| --- | --- |
| source | stdout or stderr  |
| container_id | docker container の id  |
| container_name | docker container の名前  |
| log  | 出力内容 | 

## more detail
上記のような設定でも動作はしますが、こちらの設定の場合、docker container 起動時に fluentd / td-agent が起動していないなどの理由で該当 port が listen しない場合、 docker container が起動に失敗します。

```
ERROR: for puma  Cannot start service puma: Failed to initialize logging driver: dial tcp 127.0.0.1:24224: getsockopt: connection refused
```

そこまでの強い依存関係を要求しないのであれば、以下のように `fluentd-async-connect = true` を設定すると、docker container の起動時に接続を確立的無くても contaienr は起動するようになります。

```
        logging:
            driver: "fluentd"
            options:
                fluentd-address: "localhost:24224"
                tag: "docker.logging_driver.masashi.sada"
                fluentd-async-connect: "true"
```

`fluentd-async-connect = true` にした場合は docker container の fluentd logging driver にて buffering と再送処理が行われます。
無尽蔵に buffering したりリトライを行ったりすると container の安定性に不安が出てきますので、`fluentd-async-connect = true` に設定した場合は以下のパラメータについて最適にチューニングを行いましょう。

- fluentd-buffer-limit
    - default = 8MB
- fluentd-retry-wait
    - default = 1000ms
- fluentd-max-retries
    - default = 1073741824


# parse logs
私が知る限り、fluentd logging driver では出力内容に応じてタグを出し分けたり、log 自身の内容を JSON として情報を構造化する方法をサポートしていないように見えます。

標準の項目以外のログ情報を構造化したい場合は、後続の fluentd / td-agent にて少し工夫をして parse 処理をしてあげる必要があります。

以下の Qiita などが、方法としては参考になります。
[DockerのFluentd logging driverを通したltsv形式アクセスログをパースする](http://qiita.com/tsukapah/items/7ebefb525a06aae61171)

# tag
最終的にアグリゲートされていく事を想定して、転送されるログデータの中には何かしらの形で

- container_id 
- container_name

のいずれかもしくは両方が含まれている方が扱いがしやすくなると思います。
これらは fluentd logging driver の出力する JSON にも含まれているため、タグとして表現するか、データ構造として表現するかは、アプリケーションによって扱いやすい方法を採用すると良いと思います。

タグで表現する場合は以下のような形で変数で記述できます。以下は docker-compose での例です。

```
                tag: "docker.logging_driver.masashi.sada.{{ImageName}}.{{.ID}}"
```

使用できる変数の詳細は以下ドキュメントを参照ください。
<https://docs.docker.com/engine/admin/logging/log_tags/>

# conclusion
使い方は適材適所ですが、 container が出力する内容を適切に capture 出来るという意味で fluentd logging driver は便利なので、現場の要件にあわせて使用していきましょう。