LoginSignup
14
4

More than 1 year has passed since last update.

ECS ログ出力カスタマイズ FireLens でログの出力先を分岐させてみた

Posted at

はじめに

前回の記事 : FireLens の設定方法をわかりやすく整理してみた では、FireLens からログ転送を指定する方法を整理しました。ログ転送先が、1 種類で十分なときは、Amazon ECS の Task 定義の設定を変えるだけで、簡単に転送先の指定が可能です。

このように JSON で logConfiguration.options を指定することで、Kinesis Data Firehose 経由で S3 に保存が出来ます。

                        省略
            "logConfiguration": {
                "logDriver": "awsfirelens",
                "secretOptions": null,
                "options": {
                    "Name": "kinesis_firehose",
                    "region": "ap-northeast-1",
                    "delivery_stream": "my-stream"
                }
            },
                        省略

しかし、ログの転送先を 2 種類以上にするときには、別の設定方法となります。FireLens のコンテナとして稼働する、Fluent Bit や Fluentd の設定ファイルを作成することで、好きなようにログの転送先を指定できます。

image-20221016231143002.png

 

例えば、次のような使い方が考えられます。

  • アプリケーションのアクセスログ : 大量にログが出力されるので、保存料金が安価な Amazon S3 に格納する。Athena を使って、S3 に貯めたログを SQL クエリーで検索できるようにする。
  • アプリケーションのエラーログ : AWS のマネージメントコンソールで誰でも検索が出来る、CloudWatch Logs に格納する。

 

例を挙げると、ECS Task で稼働している mainapp コンテナのアプリが、以下の 2 種類のログを標準出力に出しています。ログの level に応じて、info は S3 に格納し、warning は CloudWatch Logs に格納することが可能です。

image-20221016232613000.png

ログ分岐の流れ

どのようにログ分岐を行うか、流れを整理してみます。詳細は省略するので、ざっくりとした内容です。

まず、アプリケーションのログを標準出力に出力することで、そのログを FireLens のコンテナに渡せます。(Fluent ロガーを使う方法もありますが、割愛します)

FireLens がアプリケーションのログを受け取ったときに、FILTER という機能をつかって ECS に関するメタデータを付与します。そして、もともとのアプリケーションのログは、log キーに格納されます。

image-20221016233702152.png

FireLens が変換した log を使って、CloudWatch や Kinesis Data Firehose といった転送先を分岐することが出来ます。例えば、次の記事が参考になります。

今回の記事の環境では、アプリケーションログが JSON で出来ているので、log を更にパースします。パースした方が CloudWatch Logs などの検索で便利です。パースすると、log が分解され、以下の形になります。

image-20221016234629435.png

そして、重要な概念の一つとして、Fluent Bit には、ログをどのように扱うかコントロールするための tag という概念があります。例えば、irregularlog タグが付いているログは、CloudWatch に送り、mainapp-firelens-hogehoge タグが付いているログは、Kinesis Data Firehose に送る設定が可能です。

Fluent Bit の OUTPUT にかかわる設定を抜粋します。Match で指定しているのが、処理対象にするタグを正規表現で指定しています。

Name で指定している cloudwatch_logskinesis_firehose が、ログ転送先(正確には Plugin 名) を指定しています。次の URL で、利用できる Plugin の一覧が確認可能です。

[OUTPUT]
    Name   cloudwatch_logs
    Match  irregularlog
    auto_create_group true
    log_group_name /aws/firelens/firelens-testapp
    log_stream_prefix from-fluent-bit-
    region ap-northeast-1

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

Tag を書き換えるための rewrite_tag プラグインがあります。特定の条件にヒットしたものを対象に、タグを書き換えることが出来るので、条件ごとにログ転送先をコントロールできます。

[FILTER]
    Name          rewrite_tag
    Match         *-firelens-*
    Rule          $level ^(warning|error|fatal|panic)$  irregularlog false
    Emitter_Name  re_emitted

 

例えば、上記の rewrite_tag プラグインに関する設定をすることで、levelwarning or error or fatal or panic となっている場合は、irregularlog にタグを書き換えることが出来ます。

タグの書き換えや、タグごとの出力先の指定により、うまくログ転送先をコントロールできます。

image-20221017000402957.png

なお、FireLens では、デフォルトで以下の形式のタグが付与されます。

  • <コンテナ名>-firelens-<タスクID>

つまり、コンテナ名が mainapp で、タスク ID が dcef9dee-d960-4af8-a206-46c31a7f1e67 の場合、タグは mainapp-firelens-dcef9dee-d960-4af8-a206-46c31a7f1e67 となります。この辺りも意識すると Fluent Bit のコンフィグがしやすくなるので、覚えておくとよいでしょう。

詳細は以下の URL もご確認ください。

 

説明が長くなりましたが、上記のログ分岐の流れを実際に設定してみましょう。

ローカル検証 : Fluent Bit

Fluent Bit の動作確認を、実際の FireLens で行うのは時間がかかって大変なので、まずはローカル環境で動作確認をしていきます。

FireLens で使われている Fluent Bit のコンテナイメージは、以下の ECR Gallery で公開されています。これを使って動作確認を進めます。

まず、作業用ディレクトリを作成します。

mkdir ~/temp/firelens/spilit_logs/

 

Fluent Bit の conf ファイルを作成します。localtest.conf という名前を付けます。

[SERVICE]
    Flush     1
    Log_Level info
    Parsers_File /fluent-bit/etc/parsers_json.conf

[INPUT]
    NAME   dummy
    Dummy  {"log":"{\"level\":\"info\",\"msg\":\"this is Info Log\",\"time\":\"2022-10-16T10:16:41Z\"}"}
    Tag    mainapp-firelens-hogehoge

[INPUT]
    NAME   dummy
    Dummy  {"log":"{\"level\":\"warning\",\"msg\":\"this is warning Log\",\"time\":\"2022-10-16T10:16:41Z\"}"}
    Tag    mainapp-firelens-hogehoge

[FILTER]
    Name         parser
    Match        *-firelens-*
    Key_Name     log
    Parser       json
    Preserve_Key false
    Reserve_Data true

[FILTER]
    Name          rewrite_tag
    Match         *-firelens-*
    Rule          $level ^(warning|error|fatal|panic)$  irregularlog false
    Emitter_Name  re_emitted

[OUTPUT]
    Name   stdout
    Match  *-firelens-*

[OUTPUT]
    Name   stdout
    Match  irregularlog

 

重要なところをいくつか抜粋します

  • Parsers_File /fluent-bit/etc/parsers_json.conf : JSON を Parse するためのファイルを指定します。
[SERVICE]
    Flush     1
    Log_Level info
    Parsers_File /fluent-bit/etc/parsers_json.conf

 

  • Dummy {"log":"{\"level\":\"info\",\"msg\":\"this is Info Log\",\"time\":\"2022-10-16T10:16:41Z\"}"} : ローカルで動作確認するための、ダミーの文字列を指定します。この文字列が、動作確認に使われます
  • Tag mainapp-firelens-hogehoge : この文字列に付与する tag を指定します
[INPUT]
    NAME   dummy
    Dummy  {"log":"{\"level\":\"info\",\"msg\":\"this is Info Log\",\"time\":\"2022-10-16T10:16:41Z\"}"}
    Tag    mainapp-firelens-hogehoge

[INPUT]
    NAME   dummy
    Dummy  {"log":"{\"level\":\"warning\",\"msg\":\"this is warning Log\",\"time\":\"2022-10-16T10:16:41Z\"}"}
    Tag    mainapp-firelens-hogehoge

 

Parser をどのように行うかの指定です。tag *-firelens-* にマッチしたログに対して、log のキーに対する値を、JSON でパースします。

[FILTER]
    Name         parser
    Match        *-firelens-*
    Key_Name     log
    Parser       json
    Preserve_Key false
    Reserve_Data true

 

JSON で Parse したあとに、ログに含まれる level が、正規表現の ^(warning|error|fatal|panic)$ に引っかかったときに、Tag をirregularlog に書き換えます。

[FILTER]
    Name          rewrite_tag
    Match         *-firelens-*
    Rule          $level ^(warning|error|fatal|panic)$  irregularlog false
    Emitter_Name  re_emitted

 

次に、JSON を Parse するためのファイルを作成します。parser_json.conf

[PARSER]
    Name        json
    Format      json
    Decode_Field_AS    escaped    log

Dockerfile を作成します。上記で作成した、localtest.confparsers_json.conf を格納します。

FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:init-2.28.3

COPY localtest.conf /fluent-bit/etc/localtest.conf
COPY parsers_json.conf /fluent-bit/etc/parsers_json.conf

Build

docker build -t firelens_localtest_spilit_logs .

Bash 起動してコンテナ実行

docker run -it --rm firelens_localtest_spilit_logs bash

コンテナ内で以下のコマンドを実行すると、動作確認が出来ます。

/fluent-bit/bin/fluent-bit -c /fluent-bit/etc/localtest.conf

実行例

  • level が info のものは、tag が mainapp-firelens-hogehoge のままとなっている
  • level が warning のものは、tag が irregularlog に書き換わっている
[0] mainapp-firelens-hogehoge: [1665926237.385715351, {"level"=>"info", "msg"=>"this is Info Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] irregularlog: [1665926237.385768703, {"level"=>"warning", "msg"=>"this is warning Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] mainapp-firelens-hogehoge: [1665926238.385717828, {"level"=>"info", "msg"=>"this is Info Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] irregularlog: [1665926238.385779690, {"level"=>"warning", "msg"=>"this is warning Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] mainapp-firelens-hogehoge: [1665926239.385729496, {"level"=>"info", "msg"=>"this is Info Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] irregularlog: [1665926239.385791964, {"level"=>"warning", "msg"=>"this is warning Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] mainapp-firelens-hogehoge: [1665926240.385712879, {"level"=>"info", "msg"=>"this is Info Log", "time"=>"2022-10-16T10:16:41Z"}]
[0] irregularlog: [1665926240.385772103, {"level"=>"warning", "msg"=>"this is warning Log", "time"=>"2022-10-16T10:16:41Z"}]

Kinesis Data Firehose 作成

ローカルで動作確認ができたので、AWS 上の設定に移ります。

適当に Kinesis Data Firehose を作成します。記事のテーマではないので、読み飛ばして大丈夫です。興味があるかたはどうぞ。

image-20221016174024456.png

Source は Direct Put

image-20221016174249077.png

出力先を指定

Dynamic Partitioning を有効化 : 詳細はこちら : https://qiita.com/sugimount-a/items/edd136364a8e0d6cb725

image-20221016224047724.png

日付を使って、S3 にパーティションを作成する

.time | strptime("%Y-%m-%dT%H:%M:%SZ") | strftime("%Y-%m-%d")

firelens/date=!{partitionKeyFromQuery:logdate}/

image-20221016222555747.png

Create

image-20221016175250943.png

作成処理が進む

image-20221016175320426.png

Docker Image 作成

FireLens で動かす Fluent Bit の動作をカスタマイズしていくために、コンテナイメージを作成します。ECS on EC2 だと、S3 経由で読み込ませる方法が取れますが、ECS on Fargate の場合は基本的にコンテナイメージを作成する方法となります。

Fluent Bit の Config ファイルとして、extra.conf を作成します。

  • SERVICE の欄で、JSON をパーサーするためのファイルを指定
  • OUTPUT の欄で、出力先の CloudWatch Logs のグループ名などを指定
  • OUTPUT の欄で、作成した Kinesis Data Firehose の名前を指定
[SERVICE]
    Parsers_File /fluent-bit/etc/parsers_json.conf

[FILTER]
    Name         parser
    Match        *-firelens-*
    Key_Name     log
    Parser       json
    Preserve_Key false
    Reserve_Data true

[FILTER]
    Name          rewrite_tag
    Match         *-firelens-*
    Rule          $level ^(warning|error|fatal|panic)$  irregularlog false
    Emitter_Name  re_emitted

[OUTPUT]
    Name   cloudwatch_logs
    Match  irregularlog
    auto_create_group true
    log_group_name /aws/firelens/firelens-testapp
    log_stream_prefix from-fluent-bit-
    region ap-northeast-1

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

[OUTPUT]
    Name   cloudwatch_logs
    Match  *
    auto_create_group true
    log_group_name /aws/firelens/debug
    log_stream_prefix from-fluent-bit-
    region ap-northeast-1

parsers_json.conf はローカルで動作確認したものをそのまま利用

[PARSER]
    Name        json
    Format      json
    Decode_Field_AS    escaped    log

Dockerfile をこのように指定

FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:init-2.28.3

COPY extra.conf /fluent-bit/etc/extra.conf
COPY parsers_json.conf /fluent-bit/etc/parsers_json.conf

コンテナイメージをビルド

docker build -t xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/firelens-my-log-router:0.0.1 .

docker push

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com
docker push xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/firelens-my-log-router:0.0.1

Task 定義を作成

Task 定義を作成していきます。若干複雑な作業なので、丁寧に確認していきましょう。

image-20221016181831677.png

Fargate を指定

image-20221016181859830.png

Task 定義の名前を指定。Task Role などは、ログ転送先へ転送するための権限が必要なので、注意しましょう。

image-20221016181952033.png

Log router integration の欄が、FireLes の欄です。

  • type を fluentbit にする
  • image に、自分が作成した Fluent Bit のコンテナイメージを指定

image-20221016180208181.png

log_router が追加されたので、これをクリックします

image-20221016182233134.png

log_router そのもののログ出力は、CloudWatch logs を指定します

image-20221016180554486.png

Add Container を押します

image-20221016182343613.png

自分たちが持っているメインのアプリケーションが稼働するコンテナを指定します。このアプリケーションコンテナはこちらの記事で作成しました。

image-20221016182453517.png

Log configuration の個所で、awsfirelens を選びます。

image-20221016182545556.png

Add を押して追加します。

image-20221017005113426.png

追加した mainapp を再度選択して、内容を更新します。

image-20221016182612761.png

Log configuration の個所にある、Name に紐づく ×を押したあとに、Update を押します。

image-20221016182640034.png

Configure via JSON を指定

image-20221016180617841.png

FireLens の Config ファイルの指定方法は、firelensConfiguration から行います。

image-20221016180916443.png

変更前

            "firelensConfiguration": {
                "type": "fluentbit"
            },

変更後

  • 独自に作成した Fluent Bit コンテナイメージ 内に格納した、/fluent-bit/etc/extra.conf を読みこませる指定
            "firelensConfiguration": {
                "type": "fluentbit",
                "options":{
                   "config-file-type": "file",
                   "config-file-value": "/fluent-bit/etc/extra.conf"
                }
            },

こんな感じです。

image-20221016181028352.png

Save を押します。

image-20221017005313500.png

Create を押します。

image-20221016181113548.png

タスク定義が作成されました。

image-20221016182732834.png

サービスを作成

適当にサービスを作成して、インターネット上に公開します。

image-20221016182909326.png

ECS Exec の有効化したあとに、再度 Task を強制的に再配置。

aws ecs describe-services --cluster test-cluster01 --services firelens-testapp-service
aws ecs update-service --cluster test-cluster01 --service firelens-testapp-service --enable-execute-command
aws ecs describe-services --cluster test-cluster01 --services firelens-testapp-service

動作検証

これで準備は整いました!実際に FireLes から、CloudWatch Logs と Kinesis Data Firehose + S3 にログが格納されているか確認します。まず、ログを生成するために、公開したサービスにアクセスします。

image-20221016183656961.png

CloudWatch Logs で、/aws/firelens/firelens-testapp が自動生成されています

image-20221016223637203.png

Streams も適当に選択します

image-20221016223701228.png

warning のログのみ出力されています。info ログは、CloudWatch Logs に出力されていません。

image-20221016223806739.png

info ログは、Kinesis Data Firehose 経由で S3 に出力されています。

image-20221016223901617.png

実際の Object の中身を確認してみます。

image-20221016223921102.png

こんな中身になっています。info ログが出力されていて、想定通りです。

{"level":"info","msg":"this is Info Log","time":"2022-10-16T16:02:51Z","container_name":"mainapp","source":"stdout","container_id":"3f51a08699864c0299088cc6ef1824c3-787454787","ecs_cluster":"test-cluster01","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3","ecs_task_definition":"firelens-logsplit-task-def:2"}
{"level":"info","msg":"this is Info Log","time":"2022-10-16T16:02:51Z","container_id":"3f51a08699864c0299088cc6ef1824c3-787454787","container_name":"mainapp","source":"stdout","ecs_cluster":"test-cluster01","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3","ecs_task_definition":"firelens-logsplit-task-def:2"}
{"level":"info","msg":"this is Info Log","time":"2022-10-16T16:03:21Z","container_id":"3f51a08699864c0299088cc6ef1824c3-787454787","container_name":"mainapp","source":"stdout","ecs_cluster":"test-cluster01","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3","ecs_task_definition":"firelens-logsplit-task-def:2"}
{"level":"info","msg":"this is Info Log","time":"2022-10-16T16:03:21Z","container_id":"3f51a08699864c0299088cc6ef1824c3-787454787","container_name":"mainapp","source":"stdout","ecs_cluster":"test-cluster01","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3","ecs_task_definition":"firelens-logsplit-task-def:2"}
{"level":"info","msg":"this is Info Log","time":"2022-10-16T16:03:51Z","container_id":"3f51a08699864c0299088cc6ef1824c3-787454787","container_name":"mainapp","source":"stdout","ecs_cluster":"test-cluster01","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3","ecs_task_definition":"firelens-logsplit-task-def:2"}
{"level":"info","msg":"this is Info Log","time":"2022-10-16T16:03:51Z","container_id":"3f51a08699864c0299088cc6ef1824c3-787454787","container_name":"mainapp","source":"stdout","ecs_cluster":"test-cluster01","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3","ecs_task_definition":"firelens-logsplit-task-def:2"}

付録 : Fluent Bit 設定ファイルを確認

ECS 上で稼働している FireLens コンテナの中身を見て、conf ファイルを確認します。

ECS Exec で、FireLens のコンテナ内で bash を起動。

aws ecs execute-command \
       --cluster test-cluster01 \
       --task 3f51a08699864c0299088cc6ef1824c3 \
       --container log_router \
       --interactive \
       --command "bash"

中身を確認

  • @INCLUDE /fluent-bit/etc/extra.conf が挿入されている
  • Task 定義で指定したものが、ここに INCLUDE されている
bash-4.2# cat /fluent-bit/etc/fluent-bit.conf

[INPUT]
    Name tcp
    Listen 127.0.0.1
    Port 8877
    Tag firelens-healthcheck

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

[INPUT]
    Name forward
    Listen 127.0.0.1
    Port 24224

[FILTER]
    Name record_modifier
    Match *
    Record ecs_cluster test-cluster01
    Record ecs_task_arn arn:aws:ecs:ap-northeast-1:xxxxxxxx:task/test-cluster01/3f51a08699864c0299088cc6ef1824c3
    Record ecs_task_definition firelens-logsplit-task-def:2

@INCLUDE /fluent-bit/etc/extra.conf

[OUTPUT]
    Name null
    Match firelens-healthcheck

INCLUDE されているファイルを確認。

bash-4.2# cat /fluent-bit/etc/extra.conf

[SERVICE]
    Parsers_File /fluent-bit/etc/parsers_json.conf

[FILTER]
    Name         parser
    Match        *-firelens-*
    Key_Name     log
    Parser       json
    Preserve_Key false
    Reserve_Data true

[FILTER]
    Name          rewrite_tag
    Match         *-firelens-*
    Rule          $level ^(warning|error|fatal|panic)$  irregularlog false
    Emitter_Name  re_emitted

[OUTPUT]
    Name   cloudwatch_logs
    Match  irregularlog
    auto_create_group true
    log_group_name /aws/firelens/firelens-testapp
    log_stream_prefix from-fluent-bit-
    region ap-northeast-1

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

[OUTPUT]
    Name   cloudwatch_logs
    Match  *
    auto_create_group true
    log_group_name /aws/firelens/debug
    log_stream_prefix from-fluent-bit-
    region ap-northeast-1

参考URL

14
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
4