こんにちは、電通国際情報サービス デジタルイノベーション1部の加世です。
今回は「FluentBitを利用したログルーティング」を進める際に、「FluentBitについて理解する」ことを目的とした記事となっております。 具体的なFluentBitの使い所や設計を考える前段階として、本記事を参考にしていただければと思います。
Fluent Bitについて
FluentBitは、データ(メトリクス、ログ、それ以外の生情報など)をInput情報として収集し、加工処理したうえで任意の転送先に転送します。 クラウドサービスプロバイダを利用するうえでは、既に「システム」から「サービス」に転送する仕組みを用意していることが多いため、ログルーティングについて考慮しなくても問題ないケースが多いです。
そのため、FluentBitの利用は「複数のシステム(サーバ/コンテナ)」から「様々なデータ」を「複数の宛先」に「加工」して「集約」する場合が有効であると考えています。
- FluentdとFluent Bitの違いについて
■Fluentd&Fluent Bit https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit
FluentBitは、Fluentd傘下で開発された軽量なログルータであり、Fluentdのアーキテクチャを踏まえて構築されています。
Fluent Bitの特徴
FluentBitは、大きく6種類「Input」->「Parse」->「Filter」->「Buffer」->「Router」->「Output」のPluginで構成されています。 また、「Output」プラグインは、主要なクラウドサービスプロバイダ(AWS, Azure, GCP, Datadog...etc)に対応しています。 そのため、データ転送先はアーキテクチャ・データ分析方法を踏まえて、プラグインの対応範囲はありますがさまざまなサービスを選択できます。
FluentBitは、次の点で優れていると考えています。
優れていると考えられる点
Fluent Bit
■GitHub : Fluent Bit
https://github.com/fluent/fluent-bit■Fluent Bit : Official Manual
https://docs.fluentbit.io/manual■Release Notes
https://fluentbit.io/announcements/FluentBitに関する情報は、こちらを参照してください。
検証環境と処理フローについて
検証環境は、「AWS Fargate」で「テストアプリケーションコンテナ (Firelensログドライバ付き)」「FluentBitコンテナ」を稼働しています。 また、FluentBitは、ログルーティング先として複数の転送先「CloudWatch」「S3」を指定します。
※FluentBitコンテナを使用できる環境であれば、FluentBitの基礎的な機能は検証できます。 ※検証環境のホストOSカーネルパラメータ設定によっては、挙動が変わる場合はあります。 ※FireLensログドライバは、Fargate標準出力(stdout/stderr)をFluentBitにログルーティングするためだけに使用します。
AWS FargateでFirelensログドライバを利用して、標準出力をFluentBitに送信する方式について Firelensログドライバは、仕様を細かく確認していませんが「td-agent」の仕組みでFluentBitのInputプラグイン「Forward」を利用して標準出力を転送していると思われます。 そのため、タグは「<コンテナ名>-firelens」となるため、必要に応じて「rewrite_tags」などでタグを変更することで、Outputプラグインでのタグ条件指定がしやすくなります。
処理フロー
- アプリケーション(stdout/stderr) -> Firelensログドライバ -> (forward:24224) -> サイドカーコンテナ(FluentBit) -> CloudWatch/S3
- アプリケーション(ローカルファイル) -> (tail:Volume共有マウント) -> サイドカーコンテナ(FluentBit) -> CloudWatch/S3
AWS専用のFluentBitコンテナ
https://docs.fluentbit.io/manual/installation/getting-started-with-fluent-bit
AWSに最適化されたFluentBitコンテナが提供されています。
マニュアルにしたがって、サイドカーコンテナとして起動します。aws-for-fluent-bit
AWS Fargateの場合は、「Firelens」ログドライバと連携して「aws-for-fluent-bit」が一部設定を自動生成します。
また、オプション設定をすることで追加のFluentBit設定ファイルを読み込むことも可能です。IAMロール設定について 「aws-for-fluent-bit」コンテナは出力先となる「CloudWatch」「S3」などに対して操作権限が必要になります。 そのため、Fargateコンテナを前提とした場合は「ECSタスクロール」に設定しておく必要があります。
なお、AWS以外から「CloudWatch」「S3」に転送する場合は、FluentBit向けのIAMロールを用意して「cloudwatch」「S3」プラグインでIAMロールを指定して使用できます。
Fluent Bit設計前の準備
データパイプラインの理解
FluentBitを設計するうえで、データパイプライン「Input」->「Parse」->「Filter」->「Buffer」->「Router」->「Output」を理解する必要があります。
Input
「Forward(TCPリスナポート経由のメッセージ受信)」「tail(ローカルファイスシステム上のログファイルなどのtail)」などで「生データ」の入力を受け付けます。 他にもメトリクスデータを取得するプラグインも多数用意されています。
Parse
Inputプラグインで受け取ったデータを「Parser」で処理することにより、「データ構造化」や「マルチライン処理」を行います。
「Input」「Filter」プラグインで使用できます。データ構造化 「生データ(log)」を「時間(time)」「レベル(level)」「メッセージ(message)」などのフィールドに分割します。
- 事前に用意されているParser
https://docs.fluentbit.io/manual/pipeline/parsers/configuring-parser
「Apache」「Docker」などは構造化を目的として、すでにParserが用意されています。
- 事前に用意されているParser
マルチライン処理
複数行データ(たとえば、Javaスタックトレースの「at」など)を1つのデータとして扱います。
※なお、「\n」「\t」がエスケープされずにファイル出力されますが、回避方法は執筆時点で未調査です。処理前
{ "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" } { "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" }
処理後
{ "hostname": "ip-172-24-136-132.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms\n\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)\n\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)", "thread": "main", "time": "02-Mar-2022 15:33:32.000" }
Filter
入力された「生データ」を「Filter」で加工(追加・変更・整形・削除 etc)します。
「Parser」「Multiline(Parser)」「Record Modifier」「Rewrite Tag」「Lua」「Kubernetes」などがあります。
※「AWS Metadata」はEC2向けであり、Fargate向けのものではありません。(Fargate自体は、メタデータを参照するURLは提供されています)Buffer
生データを保管する領域として、「メモリ」または「ファイルシステム(永続領域)」を選択できます。
「Service」「Input」「Output」プラグインなどで定義します。
なお、「処理間隔(メモリリフレッシュ、データ出力などのタイミング)」「各種バッファサイズ(ファイル初期読み込みサイズなど)」はチューニング要素となります。Router
https://docs.fluentbit.io/manual/concepts/data-pipeline/router
出力対象となるデータは、Input時点でデータとひもづけられたTag(または、Filterで書き換えられたTag)をもとに「識別」できるようにします。
そのうえで、正しく条件を指定することで適切な出力先に出力します。
ルーティング条件は、Outputプラグインの「Match(ワイルドカード指定のみ)」と「Match_regex」により一致条件を設定します。Output
「クラウドサービスプロバイダ向けのストレージサービス」「ローカルログファイル」「FluentBitコンテナの標準出力」などに対して「データ」を出力します。
データの構造化について
Inputデータは、「データフィールド名の追加・加工」「データ値の追加・加工」が可能です。 InputデータがJSON形式であり、すでに構造化されているデータの場合は、そのまま「フィールド名(キー名)」「値」を利用することが多いと考えられます。 ※ただし、どのようなデータでも「Filter」プラグインにより追加の加工処理は可能です。
フィールドの追加・加工
Inputデータは、「Filter」プラグインでデータフィールド名を追加・加工できます。Firelensログドライバ経由でInputした標準出力・標準エラー出力は、「container_id」「container_name」「log」「source」フィールドをInputします。
これは既に構造化されたInputデータですが、例えば「log」「source」に対して「キ名ー(フィールド名)」を統一する目的で「message」「file_path」に変換できます。また、追加の加工処理としてコンテナ内の環境変数「$HOSTNAME」の情報をもとに、「hostname」フィールドを追加できます。
Inputデータ
{ "container_id": "3885a532543547978adf8d6e9bdf729b-2449111020", "container_name": "test-container", "log": "test message.", "source": "stdout" }
{ "container_id": "625a41f4c1a241f49e7308b9g62911cb-1475094415", "container_name": "test-container", "log": "java.io.IOException: listener timeout after waiting for [60000] ms", "source": "stderr" }
加工済みデータ
{ "container_id": "3885a532543547978adf8d6e9bdf729b-2449111020", "container_name": "test-container", "file_path": "stdout", "hostname": "ip-172-24-100-100.ap-northeast-1.compute.internal", "message": "test message.", }
{ "container_id": "625a41f4c1a241f49e7308b9g62911cb-1475094415", "container_name": "test-container", "file_path": "stderr" "hostname": "ip-172-24-100-100.ap-northeast-1.compute.internal", "message": "java.io.IOException: listener timeout after waiting for [60000] ms", }
データ値の追加・加工
Inputデータは、「Filter」プラグインでデータ値を追加・加工できます。Docker標準出力などであれば、すでに「Parser」プラグインとして用意されているパーサ「docker」を利用できます。 事前に用意されているParserで構造化が難しい場合は、独自にParserを定義できます。
たとえば、以下に示す独自の「Parser」プラグイン定義は、Tomcatの標準出力ログを加工します。 これは、InputデータのログをRegexに指定した正規表現でパースして、「time」「level」「thread」「message」などのフィールド名にマッピングします。
「Parser」プラグイン定義
[PARSER] Name tomcat Format regex Regex /^(?<time>\d{1,2}-\D{3}-\d{4} \d{1,2}:\d{1,2}:\d{1,2}.\d{3}) (?<level>[^\s]+) \[(?<thread>[^\]]*)\] (?<message>.*)/ Time_Key time Time_Format %d-%b-%Y %H:%M:%S.%L Time_Offset +0900 Time_Keep On # Command | Decoder | Field | Optional Action | # ==============|==============|=========|===================| Decode_Field_As escaped message
インプットデータ
04-Mar-2022 12:34:39.072 ERROR [main] org.apache.catalina.startup.Catalina.start Server startup in 123094 ms
加工済みデータ
{ "file_path": "/usr/local/tomcat/logs/catalina.test.log", "hostname": "ip-172-24-136-164.ap-northeast-1.compute.internal", "level": "EROROR", "message": "org.apache.catalina.startup.Catalina.start Server startup in 135176 ms\n\tat com.myproject.module.MyProject.badMethod(MyProject.java:22)\n\tat com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)\n\tat com.myproject.module.MyProject.anotherMethod(MyProject.java:14)\n\tat com.myproject.module.MyProject.someMethod(MyProject.java:10)\n\tat com.myproject.module.MyProject.main(MyProject.java:6)", "thread": "main", "time": "04-Mar-2022 12:42:28.000" }
まとめ
本記事では、「FluentBitについて理解する」ことを目的として記事を作成しました。 次回の記事では、「FluentBitを実際に動かしたうえで確認した設計・設定ポイント」をお話できればと考えています。
執筆:@kase.teruyoshi、レビュー:@sato.taichi (Shodoで執筆されました)