AWS ECS で FireLens ログドライバを試したメモ

FireLens という ECS で EC2/Fargate のどちらの起動タイプでも使用できるログドライバが、パブリックプレビューで誰でも使用できるようになったので試してみたメモです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Amazon ECS タスクから FluentBit, Fluentd を利用したログルーティングを可能にする &quot;FireLens&quot; ロギングドライバの Public Preview 開始です 👏👏👏<br><br>ECS, Fargate が利用できる全リージョンで今日からお試しいただけます！<br><br>/ &quot;Amazon ECS and AWS Fargate FireLens ...&quot; <a href="https://t.co/ZJDxRyBalk">https://t.co/ZJDxRyBalk</a></p>&mdash; ポジティブな Tori (@toricls) <a href="https://twitter.com/toricls/status/1167633075280310279?ref_src=twsrc%5Etfw">August 31, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# これまでの状況

Fargate のログドライバはしばらくの間 CloudWatch Logs しか使用できず、その他のログ基盤に連携を行いたい場合は CloudWatch Logs から Lambda を発火させるか、ログドライバを使用せず共有ボリュームにログファイルを出力してサイドカーの Fluentd に tail させる等、少々複雑な方法でしか実現できなさそうだった。

そんな中、FireLens は fluentd/fluent-bit にログを連携する事が可能なドライバということで、既存のログ基盤を活かせるのではないかと注目した。

また EC2 起動タイプでは fluentd ログドライバが以前から使用できていたが、今回の FireLens とどのような違いがあるのかも併せて確認したかった。

# 準備

下記サイトに基本的な手順が記載されているのでそれに沿って進めていく。

https://github.com/aws/containers-roadmap/tree/master/preview-programs/firelens

FireLens を動作させる上で必要な要素は **`FireLens` コンテナとしてマークしたログ収集コンテナ** と **ログドライバに `awsfirelens` を指定したアプリケーションコンテナ** のみ。

あとはログ収集コンテナがログを転送する先が必要で、今回は S3 にログを配置したかったので **Kinesis Firehose** を使用することにする。

## ログ収集コンテナの設定

今回は手順でもオススメされている通りに fluent-bit を使用する。fluent-bit はプラグインの数や設定の自由度で fluentd より劣るが、C言語で実装されているため軽快に動作するので末端でのログ収集に向いている。

FireLens で使用する fluent-bit は AWS によって Kinesis Firehose と CloudWatch Logs の出力プライグインが追加された[カスタムイメージ](https://hub.docker.com/r/amazon/aws-for-fluent-bit)を使用する。この出力プライグインのオプションなどの詳細は下記リポジトで確認できる。

- https://github.com/aws/amazon-kinesis-firehose-for-fluent-bit
- https://github.com/aws/amazon-cloudwatch-logs-for-fluent-bit

FireLens コンテナとしてマークするにはタスク定義で `firelensConfiguration` を設定すれば良い。現在は JSON からしか設定できないようだが、ウェブコンソール上でも `JSONによる設定` を押せば設定可能である。

![スクリーンショット 2019-09-09 15.18.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36663/22c7dd04-7297-6788-47f4-b3900a3c931c.png)

`firelensConfiguration` はオプションでログにECSのメタデータを追加するかどうかを設定可能。

## アプリケーションコンテナの設定

ログ出力元のコンテナは標準出力にログを出すアプリケーションならなんでも良い。

`logConfiguration` の `logDriver` に `awsfirelens` を設定すれば FireLens を使用することができるが、こちらも現在は JSON からしか設定できない模様。

オプションは fluent-bit の設定ファイルで OUTPUT セクションに記述する内容をタスク定義で設定できる。ドキュメントに書かれているオプション以外にも `data_keys` など出力プラグインの設定は全て同様に記述できるようだ。

## Kinesis Firehose の設定

主題ではないので詳しくは書かないがウェブコンソール上で簡単にセットアップできるので使用したことがない方は是非使ってみてほしい。

# 実行

作成したタスク定義をECSでタスク実行させてみると、アプリケーションコンテナのログ設定が下記の表示になっていた。また、問題なく設定できていれば kinesis にもログが連携されていた。

![スクリーンショット 2019-09-09 16.42.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36663/ee7b080f-ed16-784a-c6ea-c3d69d735cfa.png)


## 実態の確認

実際にはどのようにしてログ連携されているのか気になったので、EC2 クラスターで FireLens を設定したタスクを実行して設定状態を確認してみた。

### アプリケーションコンテナ

```bash
[ec2-user@ip-10-0-0-1 ~]$ docker inspect application-container
...
            "LogConfig": {
                "Type": "fluentd",
                "Config": {
                    "fluentd-address": "unix:///var/lib/ecs/data/firelens/260d3686-c618-42bb-912d-c0878a18fb88/socket/fluent.sock",
                    "fluentd-async-connect": "true",
                    "tag": "test-firelens-260d3686-c618-42bb-912d-c0878a18fb88"
                }
            },
```

- FireLens の実態は fluentd ログドライバを使用している。
- ログ収集コンテナとの通信はECSエージェントが自動で用意した unix ソケットが設定されている。

### ログ収集コンテナ

```bash
[ec2-user@ip-10-0-0-1 ~]$ docker inspect log-container
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/ecs/data/firelens/82cd393b-0fd5-47a3-9dae-70f695e09acf/config/fluent.conf",
                "Destination": "/fluent-bit/etc/fluent-bit.conf",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/var/lib/ecs/data/firelens/82cd393b-0fd5-47a3-9dae-70f695e09acf/socket",
                "Destination": "/var/run",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
```

- fluent-bit 設定ファイルと unix ソケット がログ収集コンテナに勝手にマウントされている。

```bash
[ec2-user@ip-10-0-0-1 ~]$ cat /var/lib/ecs/data/firelens/82cd393b-0fd5-47a3-9dae-70f695e09acf/config/fluent.conf

[INPUT]
    Name forward
    unix_path /var/run/fluent.sock

[FILTER]
    Name   grep
    Match test-firelens*
    Regex  log ^.*[aeiou]$

[FILTER]
    Name   grep
    Match coupon-firelens*
    Exclude log ^[a-z][aeiou].*$

[OUTPUT]
    Name firehose
    Match test-firelens*
    data_keys log
    delivery_stream test-kinesis
    region ap-northeast-1
```

- fluent-bit 設定ファイルはタスク定義で設定した内容が FILTER セクションと OUTPUT セクションに反映されていた。
- INPUT セクションはアプリケーションコンテナと同様に unix ソケットによる通信が設定されている。

# まとめ

- FireLens の実態は fluentd ログドライバと fluent-bit をタスク定義に記述された内容をもとに自動で設定するラッパーのようなもの。
- メリット
    - Fargate ではこれまで fluentd ログドライバを使用する選択肢がなかったので非常に大きなアップデート。
    - unix ソケットを自動で設定してくれるので同一インスタンス内で複数のログ収集コンテナが起動しても問題ない。
- デメリット
    - ~~**現時点では** fluent-bit 設定ファイルはECSエージェントによって強制的に上書きされるため、 タスク定義に設定可能な項目以外は独自の設定ができない。~~
        - 特にバッファ周りなど SERVICE セクションが全く設定できないので、ログ自体が重要な役割を持つシステムに本番投入するには時期尚早な所感 (プレビューなので当たり前)
        - プレビュー後にカスタム構成がサポートされると記載されているので今後に期待。
        - https://github.com/aws/containers-roadmap/tree/master/preview-programs/firelens#3-specifying-your-own-configuration
    - **10/30 追記:** アップデートにより Custom Configuration File として独自の設定ができるようになったようです。
        - https://docs.amazonaws.cn/en_us/AmazonECS/latest/userguide/using_firelens.html#firelens-taskdef

書き殴ったメモなので認識間違い等ありましたらコメントください。