FluentdをDockerで動かしてみる

この記事は MicroAd Advent Calendar 2022 の7日目の記事です。

https://qiita.com/advent-calendar/2022/microad

# 概要

Fluentdでログデータの収集をDocker環境で試す手順について書きます。

想定読者
- Dockerに環境があり、Dockerの基本操作が分かる
- Fluentdについて初心者

# Fluentdとは

Fluentdは、ログデータの収集、集約、変換などを担うOSSです。
例えば、NginxやApacheなどのWebサーバのアクセスログをFluentdを使ってMySQLやElasticSearchに転送することができます。

https://docs.fluentd.org/

## ちなみに）td-agent との違い

Fluentdの説明にはよく **「td-agent」** が出てきますが、これはFluentdの安定版にした配布用パッケージで、Treasure Data社が提供しているものです。

以下のような違いがあります。

- FluentdはRuby gemsかソースコードで配布、td-agentはRPMやDEBで配布されている
- Fluentdは設定は素のままでinitスクリプトもないが、td-agentはいくつかは推奨設定がされておりinitスクリプトもある

そのため、実際は運用しやすさからtd-agentを使うことが多いかと思いますが、本体の挙動自体は同じなため多くの部分ではFluentd=td-agentに読み替えが可能です。

詳細は、公式FAQに記載がありますのでそちらをご確認ください。

> What are the differences between td-agent and Fluentd?

https://www.fluentd.org/faqs

さらに余談ですが、最近は **「calyptia-fluentd」** というパッケージも用意されています。
こちらは、Calyptia社がメンテナンスしており同梱されているRubyのバージョンが3系で新しく、高速化、最適化の恩恵を受けられるようです。

https://calyptia.com/2021/06/11/announcing-calyptia-fluentd-distribution/

# Dockerで動かしてみる

## 準備

以下のようにファイルを準備します。

```
❯ tree
.
├── config
│   └── fluent.conf
└── docker-compose.yml

1 directory, 2 files
```

```docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 80:80
    logging:
      driver: "fluentd"
      options:
        fluentd-address: localhost:24224
        tag: "docker.{{.Name}}"
    depends_on:
      - fluentd
  fluentd:
    image: fluent/fluentd:v1.15.3-1.0
    volumes:
      - ./config:/fluentd/etc
    ports:
      - 24224:24224
      - 24224:24224/udp
```

```fluent.conf
<source>
  @type forward
</source>

<match docker.**>
  @type stdout
</match>
```

## 動作

以下でコンテナを起動させ、ログを見れる状態にしておきます。
```
docker compose up -d
docker compose logs -f
```
この状態で、ブラウザか別ターミナルで`curl`コマンドを用いて`localhost`にアクセスします。
すると、以下のようにログが出力されるかと思います。

```
01-nginx-1    | 172.18.0.1 - - [07/Dec/2022:02:08:26 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.74.0" "-"
01-fluentd-1  | 2022-12-07 02:08:26.000000000 +0000 docker.01-nginx-1: {"source":"stdout","log":"172.18.0.1 - - [07/Dec/2022:02:08:26 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.74.0\" \"-\"","container_id":"e50625bf3a1cfeae0bea0fbf3c724761eb16a37838ef297f854115e004664196","container_name":"/01-nginx-1"}
```

Nginxにアクセスした際のアクセスログがfluentdのDockerコンテナに転送されているのが確認できればOKです。

## 解説: ログを収集される側（Nginx）

Nginxの部分の説明は省略し、以下のロギングドライバについて説明します。

```
    logging:
      driver: "fluentd"
      options:
        fluentd-address: localhost:24224
        tag: "docker.{{.Name}}"
```

Dockerにはロギング・ドライバ（logging driver）というコンテナのログを記録するための仕組みがあります。
ログの形式は、driverオプションを指定することで選択できます。デフォルトでは、`driver: json-file`となっており、JSON形式で記録されています。

https://docs.docker.jp/config/container/logging/configure.html

今回は、docker-compose.ymlで明示的にFluentdロギングドライバを指定しました。
指定方法は見たとおりですが、`driver: fluentd`の部分で、Fluentdのためのいくつかのオプションを設定しています。

`fluentd-address` は送信先となるFluentdのアドレスです。今回はFluentdのコンテナを24224番ポートでポートバインディングしているため、`localhost:24224`を指定することでFluentdのコンテナに接続できようになっています。

https://docs.docker.jp/config/container/logging/fluentd.html


`tag`は、ログ出力を識別するために設定しています。`"docker.{{.Name}}"`と指定することで、`docker.<コンテナ名>`のような形式でタグが付与されログ出力されます。デフォルトでは、コンテナIDの先頭12文字となります。

コンテナ名以外にイメージ名などをタグに入れることが可能です。詳細は以下をご参照ください。

https://docs.docker.jp/config/container/logging/log_tags.html

注意として、Nginxのコンテナが起動した際にFluentdに接続できるようになっていないとログの記録に失敗します。
以下のように起動順序を制御するか、起動後に `docker compose restart nginx` を実行し、Nginxを起動し直す必要があります。

```
depends_on:
      - fluentd
```

## 解説: ログを収集する側（Fluentd）

Dockerとしては以下を設定しています。

- Fluentd公式イメージを指定(執筆時点での最新バージョンを指定しています)
- 設定ファイルが含まれるディレクトリをバインドマウント
- Fluentdへの接続のため24224番ポートをポートバインド

https://hub.docker.com/r/fluent/fluentd/

```
fluentd:
    image: fluent/fluentd:v1.15.3-1.0
    volumes:
      - ./config:/fluentd/etc
    ports:
      - 24224:24224
      - 24224:24224/udp
```

Fluentdの設定ファイルは、HTMLのような構造をしています。
各設定のまとまりをディレクティブと呼び、ディレクティブはタグとパラメータで構成されます。

以下の例では、`<source>`ディレクティブと`<match>`ディレクティブがあり、`<source>`ディレクティブ内には`<source>`タグと`@type`パラメータが指定されている構成となっています。
タグは引数を取るものがあり、`<match>`タグの`docker.**`の部分が引数です。

```
<source>
  @type forward
</source>

<match docker.**>
  @type stdout
</match>
```

`<source>`ディレクティブの設定では、ログをFluentdに取り込むための入力のための設定です。
typeでは`forward`を指定しているため、`in_forward`プラグインによってネットワーク経由でのログの読み込みを行います。また、`in_forward`プラグインはデフォルトで24224番ポートを利用するため、今回Dockerのポートバインドで指定していました。

`<match>`ディレクティブの設定では、取り込んだログをどう処理し出力するかを設定します。引数では、処理対象を識別するタグを設定でき、今回はDockerのロギング・ドライバで指定したタグとマッチするように指定しています。
処理内容は、`stdout`プラグインを用いて標準出力で出力するのみを設定しています。そのため、動作確認時ではFluentdのコンテナで標準出力として受け取ったNginxのアクセスログが出力されました。

# まとめ

かなり簡単にではありますが、FluentdをDockerで動かして挙動を確認してみるまでについて書いてみました。
拙い文章ではありますが、誰かの参考になれば幸いです。