FireLens for Amazon ECS の設定について調べる

モチベーション
- 現在 ECS で稼働しているアプリケーションはログを CloudWatch Logs に出力している
- それとは別に特定のログを S3 に出力したい
- CloudWatch Agent をサイドカーコンテナとして立てて CloudWatch Logs 経由で Firehose 使うという手もあるが、コスト的に高くつく&構成も無駄に複雑化してしまう
- FireLens であればシンプルな構成で実現できそう

FireLens は Fluentd / FluentBit と連携してログを特定のサービス等に転送する仕組みを簡単に構築できる Amazon ECS の機能
正式名称は「FireLens for Amazon ECS」

FireLens のタスク定義の例
Log Router コンテナ (FluentBit 自身) のログと、Log Router の設定が別のコンテナに記述するようになってたりと分かりづらい。( Fluent Bit / Fluentd を FireLens という機能として中途半端に抽象化していることが原因かもしれない )
タスク定義の例
{
"family": "firelens-example-firehose",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecs_task_iam_role",
"containerDefinitions": [
{
"name": "log_router",
"image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable",
"cpu": 0,
"memoryReservation": 51,
"portMappings": [],
"essential": true,
"environment": [],
"mountPoints": [],
"volumesFrom": [],
"user": "0",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/ecs-aws-firelens-sidecar-container",
"mode": "non-blocking",
"awslogs-create-group": "true",
"max-buffer-size": "25m",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "firelens"
},
"secretOptions": []
},
"systemControls": [],
"firelensConfiguration": {
"type": "fluentbit"
}
},
{
"essential": true,
"image": "public.ecr.aws/docker/library/httpd:latest",
"name": "app",
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Name": "firehose",
"region": "us-west-2",
"delivery_stream": "my-stream",
"log-driver-buffer-limit": "2097152"
}
},
"memoryReservation": 100
}
]
}

カスタム設定ファイル
上記の例では、タスク定義(JSON)から動的に Log Route 用の設定ファイルを生成する方式だが、カスタム設定ファイルとして事前にファイルを用意しておくこともできる。
その場合、タスク定義の logConfiguration
の以下のキーを使用する
{
"containerDefinitions": [
{
"essential": true,
"image": "906394416424.dkr.ecr.us-west-2.amazonaws.com/aws-for-fluent-bit:stable",
"name": "log_router",
"firelensConfiguration": {
"type": "fluentbit",
"options": {
"config-file-type": "s3 | file",
"config-file-value": "arn:aws:s3:::amzn-s3-demo-bucket/fluent.conf | filepath"
}
}
}
]
}

-
config-file-type
- カスタム設定ファイルのソースの場所。使用できるオプションは、s3 または file です。
-
config-file-value
- カスタム設定ファイルのソース。
- s3 設定ファイルタイプを使用する場合、設定ファイルの値は Amazon S3 バケットとファイルの完全な ARN です。
- file 設定ファイルタイプを使用する場合、設定ファイルのこの値は、コンテナイメージ内、またはそのコンテナにマウントされているボリューム上に存在する設定ファイルへの完全パスです。

AWS Fargate でホストされるタスクは、file 設定ファイルタイプのみをサポートします。
Fargate だと S3 から読み込むことができないらしい...

FireLens の仕組みを深く理解する

Fluent Bit
Fluent Bit の概要、成り立ち、キーコンセプトまでは理解しておきたい

FireLens によって構築されるロギング環境の構成イメージ
引用元: https://aws.amazon.com/jp/blogs/news/under-the-hood-firelens-for-amazon-ecs-tasks/
Application コンテナのログは、 以下2つの方法で FireLens (Fluent Bit 等) コンテナに送信される
- 標準出力ログ: Fluentd Docker ログドライバを介して Unix ソケット経由
- TCP ソケットよりパフォーマンスに優れる
- Fluent Forward Protocol メッセージ (Fluent Logger ライブラリを使用) : TCPソケット経由
- アプリケーションコードで、タグを付けた形でログを送出することができる

FluentBit などの設定ファイルは、タスク定義の内容を元に FireLens によって生成される。
ユーザー独自の設定ファイルは include ディレクティブを使用して、FireLens が生成した設定ファイルにインポートされる
設定ファイルは Log Router コンテナの以下の path にマウントされる
- Fluent Bit:
/fluent-bit/etc/fluent-bit.conf

Fluent Bit のログ処理パイプライン
引用元: https://aws.amazon.com/jp/blogs/news/under-the-hood-firelens-for-amazon-ecs-tasks/

AWS for Fluent Bit
AWS Fluent Bit Plugin を含む Fluent Bit のリポジトリ

FireLens のユースケースごとの設定例

複数のログソース(stdout とログファイル)からログを受け取る設定
を見ていく
- FireLens が生成する設定において、コンテナの標準出力に対して以下の形式でタグを付与する
{container name}-firelens-{task ID}

file type でカスタム設定を提供するやりかた

別のやりかたもあるらしい
この設定では、
- Application コンテナログ(標準出力) → CloudWatch Logs
- 設定格納場所: Task定義(JSON)の app コンテナの logConfiguration
- Application コンテナの
/logs/app.log
→ S3- 設定格納場所: S3 バケット (Log Router コンテナの環境変数に設定)
という形でログの出力先を分けることができる。
これが求めていた形に一番近いかも
ログのルーティング設定が2個所に分かれるという点が複雑だが

Init process と multi-config について
- Fluent Bit イメージのタグとして
init-xxx
と指定することで Init process を利用できる-
aws-for-fluent-bit:init-latest
oraws-for-fluent-bit:init-2.27.0
のように
-
- 環境変数として設定ファイルの場所を指定することができる
"environment": [ { "name": "aws_fluent_bit_init_s3_1", "value": "arn:aws:s3:::yourBucket/aaaaa.conf" }, { "name": "aws_fluent_bit_init_s3_2", "value": "arn:aws:s3:::yourBucket/bbbbb.conf" }, { "name": "aws_fluent_bit_init_file_1", "value": "/ecs/s3.conf" } ]
- Init process として S3 バケットから設定ファイルを読み込む場合、Taskロールに以下の権限が必要
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetBucketLocation" ], "Resource": "*" } ] }

Init process の動作
- ECS Task Metadata から情報を取得し、環境変数にセットする
-
aws_fluent_bit_init_s3_
,aws_fluent_bit_init_file_
という prefix つきの環境変数から値を取り出し、指定の場所から設定ファイルを読み込む - タスク定義から Fluent Bit の設定ファイルを生成、@INCLUDE ディレクティブで前述の設定ファイルを読み込ませる
- 読み込ませるファイルが Parser 設定の場合は特殊な処理を行う... (今回不要なのでスルー)

Init process による起動コマンドの変更
Init process を有効化 ( Log router コンテナに init-xxx
イメージを利用する ) すると、 Fluent Bit の起動コマンドが変化する
- 設定ファイルは
/init/fluent-bit-init.conf
を読み込むようになる-
/init/fluent-bit-init.conf
は以下の設定を読み込む-
/fluent-bit/etc/fluent-bit.conf
FireLens が Task定義から生成する従来の設定ファイル -
/init/fluent-bit-init-s3-files/your-filter.conf
ユーザーが S3 に配置した設定ファイル
-
-
例)
@INCLUDE /fluent-bit/etc/fluent-bit.conf
@INCLUDE /init/fluent-bit-init-s3-files/your-filter.conf
@INCLUDE /init/fluent-bit-init-s3-files/your-s3-output.conf

json parser が使えない?
以下のように /path/to/audit-*.log
を JSON parser で読み込もうとしたら
[INPUT]
Name tail
Path /path/to/*.log
Parser json
Tag audit
Refresh_Interval 1
Rotate_Wait 30
Skip_Long_Lines On
DB /var/log/flb_audit.db
以下のようなエラーが出ていた
[error] [input:tail:tail.3] parser 'json' is not registered

これが使えるか?
なんかイメージしてたのと違う気がする

Fluent Bit における Parser について

Fluent Bit リポジトリにあったやつ

Parse したいログは
{
"timestamp": "2025-09-11T15:46:18.182+09:00",
"record": {
"auditable": {
"id": 123,
"type": "FooBar"
},
"user": null,
"action": "create",
"changes": "....",
"remote_address": null,
"request_uuid": null
}
}

上記を元に Parser 設定は
[PARSER]
Name audit_json
Format json
Time_Key timestamp
Time_Format %Y-%m-%dT%H:%M:%S.%L%z
Time_Keep On
Decode_Field_As json record

Input でその Parser を利用するようにしたらエラーは消えた
[INPUT]
Name tail
Path /path/to/*.log
- Parser json
+ Parser audit_json
Tag audit
Refresh_Interval 1
Rotate_Wait 30
Skip_Long_Lines On
DB /var/log/flb_audit.db

Fluent Bit のログレベルを debug にする

デバッグのため Fluent Bit のログに出力してみる
stdout
フィルターは処理レコードを標準出力に表示する
[FILTER]
Name stdout
Match audit

S3 にアップした設定が init process で読み込まれていない?
After init process has processed:
fluent-bit-init.conf (new main config file generated by init process, will used to invoke Fluent Bit, path inside the image:/init/fluent-bit-init.conf)@INCLUDE /fluent-bit/etc/fluent-bit.conf @INCLUDE /init/fluent-bit-init-s3-files/your-filter.conf @INCLUDE /init/fluent-bit-init-s3-files/your-s3-output.conf
このように記述あり、 s3 にアップしたファイルが INCLUDE されるはずだが... どうも読み込まれてなさそう

Log Router コンテナに入って /init/fluent-bit-init.conf
ファイルを確認してみるが @INCLUDE
による s3 からダウンロードしたファイルの読み込みが入っていない
# cat fluent-bit-init.conf
@INCLUDE /fluent-bit/etc/fluent-bit.conf