はじめに
AWSを使ったシステム開発で、「コンテナアプリケーションのログを出すならFireLensが便利!」という考えだけが先行して、実際どのような仕組みなのかしっかり把握できていませんでした。実際に色々調べると上手いこと出来ているんだなあと思ったので紹介します!!
FireLensって何?
FireLensは、簡単に言うとECSで使用するログルーティングの仕組みです。例えば、サーバログとアプリログがあり、これらを分割して各ログだけを見ることが出来るようなシステムにしたい場合、FireLensは非常に効果的です。
ただし、FireLensというサービス自体はありません!実体は、AWSがECSのログをルーティング出来るように設定をしたfluentbit、もしくはFluentdです。
なので、改めて整理をすると、ECSのログルーティングを行う仕組みがFireLensで、FireLensを実現するのはfluentbit、もしくはFluentdです
FireLensを使用したログルーティングの流れ
① mainコンテナからfluentbitに届くまで
以下は、AWSが用意したfluentbitイメージをデフォルト設定でサイドカー的に展開した場合のタスク構成です。図の通り、AWS公式イメージを使用するとmainのコンテナからの標準出力・標準エラー出力と、24224番TCPポート宛てのログは、全てfluentbitに届く仕組みが完成しています。特別な要件が無い限りはAWS公式のfluentbitを使用するのが楽そうですね!
余談ですが、24224番ポートはFluentdがデフォルトで使用するポートだそうで、アプリケーションのfluentloggerライブラリを使用するときも、このポートが使われています!(参考)
その後、fluentbitから各AWSリソース (CloudWatch, S3, Firehose) に届いたログを送ることになるのですが、この設定は、追加のconfファイルで行います。
② fluentbitから各AWSリソースに届くまで (confファイルの設定)
fluentbitはログをタグを基にルーティングするのが基本です!confファイルでは、このタグによる振り分けの設定を行います。

しかし、タグは最初から図のように設定されているわけではありません。mainコンテナから出力されるログは、${container-name}-firelens-${task-id}というタグが付与されます。${container-name}は、タスク定義で設定するmainコンテナの名前です。ここから、confファイルでは、タグの書き換えを行ってから、書き換えたタグに基づいてログをルーティングします。
以下は、上記の設定を記載したconfファイルの例です。
[FILTER]
Name rewrite_tag
Match ${container-name}-*
Rule key value tag1 false
[OUTPUT]
Name cloudwatch_logs
Match tag1
region ap-northeast-1
log_group_name ${log_group_name}
log_stream_prefix ${prefix}
auto_create_group true
confファイルの解説です。
- ログ (json形式) の特定の
keyがvalueであるログについて、元のタグ${container-name}-firelens-${task-id}を、tag1に変換する →[FILTER]のrewrite_tag - タグが
tag1であるログについてCloudWatch Logsに出力する →[OUTPUT]
後は、作成したconfファイルをfluentbitのコンテナに盛り込むことでルーティングが実現できます。
confファイルの盛りこみ方
大きく分けて、2つ存在するので、それぞれ解説します。
ファイルの在り処①:イメージ作成時に取り込んでおく
Dockerイメージを作る際にあらかじめconfファイルを取り込んでおく方法です。この方法の手順は以下の通りです。
- AWSのfluentbit公式イメージをベースとしたDockerfileを作成したうえで、Elastic Container Repositry (ECR) にプッシュする
- タスク定義でconfファイルの場所を指定する
以下にDockerfileとタスク定義の例を示します。
① Dockerfile
FROM public.ecr.aws/aws-observability/aws-for-fluentbit:latest
COPY ./setting.conf /fluent-bit/etc/extra.conf
② タスク定義
confファイルは、log_routerコンテナのfirelensConfigurationにおけるoptionsに記述します。この時、confファイルの場所は、Dockerfileにおけるsetting.confのコピー先であることに注意してください。
{
"family": "task-with-firelens",
"...": "...",
"containerDefinitions": [
{
"name": "main",
"image": "${private-ecr-uri}/main-container:latest",
"...": "...",
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {}
}
},
{
"name": "log_router",
"image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:init-latest",
"...": "...",
"firelensConfiguration": {
"type": "fluentbit",
"options": {
"config-file-type": "file",
"config-file-value": "/fluent-bit/etc/extra.conf"
}
}
},
],
"...": "..."
}
この方法は、firelensの様々な記事でconfファイルを追加する際に説明されています。直感的な一方、confファイルを変更するたびにECRへプッシュし直さないといけなかったり、プライベートECRでイメージタグの管理などもしないといけないなどといったコストがかかるのも事実です。
そこで、次の方法を取れば、ECRの管理コストを無くすことが可能です。
ファイルの在り処②:S3から読み取る
S3にconfファイルを配置し、タスク作成時にそのファイルを読み込んで設定を反映させる方法です。注意としては、この方法を取れるAWSの公式イメージタグはinit-*が付いているものだけです。①と異なり、タスク定義の作成だけで済みます。
一方で、少し、タスク定義の記載が変わり、firelensConfigurationではなく、environment=環境変数で値を取り込むようにタスク定義に記載します。こうすることで、init-*タグが付いているイメージは追加設定を反映するようになっています。
{
"family": "task-with-firelens",
"...": "...",
"containerDefinitions": [
{
"name": "main",
"image": "${private-ecr-uri}/main-container:latest",
"...": "...",
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {}
}
},
{
"name": "log_router",
"image": "${private-ecr-uri}/fluentbit:latest",
"environment": [
{
"name": "aws_fluent_bit_init_s3_1",
"value": "${S3_bucket_arn}/fluentbit/setting.conf"
}
],
"...": "...",
"firelensConfiguration": {
"type": "fluentbit"
}
},
],
"...": "..."
}
まとめ
- FireLensはサービスではなくログルーティング (ログを一括で収集し、各ツールに転送する) の仕組み!これを実現するのはfluentbitやFluentd
- AWS公式イメージを使用すれば、既にログを収集する設定が整っている
- 追加のconfファイルを用意し、タグの書き換えにより、ログをルーティングする
- confファイルをイメージ作成時に取り込んじゃうかS3に配置してタスク作成時に設定を反映させる!
