Firelens構築記事の2回目となります。
1回目 firelensを使用した、ログ分割と監視処理
3回目 Firelensで、datadog/S3へデータを転送できるdockerイメージを作成する
githubのサンプルはfirelensとの連携まで完成しており、文章中の解説はサンプルベースで行います。
ローカルで動くサンプルの作成
fluentbitの調整をfargate上で行うと疲弊してしまうので
docker-composeで構築のサンプルを作成し、正しく動作するfluentbitの構成ファイルを作成することにしました。
docker-compose.yml
version: '3.5'
services:
web:
build: app
#image: *****/firelens:web-container
ports:
- "80:80"
depends_on:
- fluentbit
logging:
driver: fluentd
options:
fluentd-address: "localhost:24224"
fluentd-async-connect: "true"
fluentbit:
build:
context: fluentbit
# image: *****/firelens:fluentbit
env_file: ./.env
ports:
- "24224:24224"
- "24224:24224/udp"
apache-phpコンテナとfluentbitコンテナを連携させただけのcomposeファイルです。
imageのビルド目的なので、全般的にvolumeのmountを行いません。
.envファイルには事前に取得したdatadogのAPIキー、S3の認証情報等を設定して下さい。
logging driverに、fluentdを指定します。
本来のログに、fluentd用のメタデータが付与されます。
http://docs.docker.jp/engine/admin/logging/fluentd.html
fluentd-async-connectオプションは
コンテナ起動完了順により、fluentbitコンテナへログが送信出来ない場合の、バッファ処理です。
http://docs.docker.jp/engine/admin/logging/fluentd.html#fluentd-async-connect
webコンテナ
webアプリケーションコンテナの解説です。
apache(出力ログ調整部分)
サンプルでは、apacheでJSON形式のログを出力するように設定しています。
ErrorLogFormat "{\"service\":\"error.log\", \"message\":\"%M\"}"
ErrorLog /dev/stderr
LogFormat "{\"service\":\"access.log\", \"message\":\"%h - - %t %r %>s %b %{Referer}i %{User-Agent}i %D\"}" combined
CustomLog /dev/stdout combined
実サービスでは、datadogの予約済属性をここで定義しておくことで
難解なログ整形処理を行わず、datadog側でスムーズなログ管理が行えるようにしています。
https://docs.datadoghq.com/ja/logs/processing/
今回、ログをJSON形式に整形できるタイミングは
1.アプリケーション(php/apache)
2.fluentbit(filterプラグイン)
3.datadog(pipeline)
また、下記のログを全て最終的にS3に格納します。
日次50万件のアクセスログ
日次5万件のアプリケーションログ
日次1000件以下のエラー系ログ
整形タイミングはdatadogでも良いのですが、上記全てのログをdatadogに転送しなければいけなくなるので
datadogのコスト増を懸念しました。資金との兼ね合いかと思います。
https://www.datadoghq.com/pricing/#section-log-management
fluentbitでも可能ですが、設定ファイルが複雑になりそうだったので、ここは最低限としました。
結果、取り回しの容易さを考え,サンプルではアプリケーション(apache)で対応しています。
webアプリケーションでフレームワークを使用しているのであれば、ログのモジュール等で対応できるかと思います。
php
余り深く考えずに書きました。
サンプルは、アプリケーションログに相当するものは出力していません。
<?php
if (isset($_GET['exception'])) {
error_log("Exception.");
exit;
}
phpinfo();
http://localhost
➡︎アクセスログを標準出力
{"service":"access.log", "message":"172.19.0.1 - - [07/Nov/2019:02:49:33 +0000] GET / HTTP/1.1 200 24000 - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36 3457"}
http://localhost?exception
▶︎アクセスログに加えて、エラーログが標準エラー出力されます。
{"service":"error.log", "message":"Exception."}
fluentbitコンテナ
fluentbitコンテナの解説です。
firelensは、デフォルトのfirelens用のfluentbit dockerイメージが用意されているので
最低限のログ処理を行い、一箇所だけにログ送信を行うのであれば、dockerイメージは不要です。
ドキュメント
dockerhubのfirelens用dockerイメージ(fluentbit ver1.2.2)
firelens用のfluentbit dockerイメージの要件
・verisonは1.2.2
・カスタム構成ファイルは、fargateではファイルパスのみ指定できる
For tasks using the Fargate launch type, the only supported config-file-type value is file.
⇨fluentbit.conf,Parsers_File,Plugins_File,Streams_File、fluentbit外部プラグインを使う場合、ボリュームのマウントが必要
今回のfluentbitの要件
・fluentbitで、ログの内容により、出力先を分けて送信したい
・出力先はdatadog(標準プラグイン)と、S3(外部プラグイン)の二箇所
構成が複雑になる恐れがあったため、aws提供のものは使わず、カスタムdockerイメージを使用します。
fluentbit構成ファイル
dockerfile
長いので省略します。
dockerfile
カスタムした構成ファイル群をコンテナに内包してビルドを行います。
fluent-bit-go-s3プラグインの生成は、マルチステージビルドを使用しています。
fluent-bit.conf
ログ処理の概要です。
1.[INPUT]24224ポートで、webコンテナからの標準出力を取得
2.[PARSER/FILTER]「log」キーの値は、webコンテナから送信されたjson文字列が入っているので
パース処理を行い、大元のJSONと結合する。※元のlogキーは削除
3.[STREAM PROCESSOR]stream_processorを使用し、serviceキーの中身でログを分類
4.[ROUTE/OUTPUT]分類したログを、それぞれに適した出力先に送信する
# https://docs.fluentbit.io/manual/configuration/file
[SERVICE]
Log_Level info
Streams_File stream_processor.conf
Parsers_File parser.conf
[INPUT]
Name forward
Tag service-firelens-xxx
alias combine_log
Listen 0.0.0.0
Port 24224
# https://docs.fluentbit.io/manual/filter/parser
[FILTER]
Name parser
Match *
Key_Name log
Parser json
Preserve_Key false
Reserve_Data true
[OUTPUT]
Name datadog
Match error
Host http-intake.logs.datadoghq.com
TLS on
apikey ${DATADOG_APIKEY}
dd_source ${DATADOG_SOURCE}
[OUTPUT]
Name datadog
Match ap
Host http-intake.logs.datadoghq.com
TLS on
apikey ${DATADOG_APIKEY}
dd_source ${DATADOG_SOURCE}
[OUTPUT]
Name s3
Match access
AccessKeyID ${OUT_S3_ACCESS_KEY}
SecretAccessKey ${OUT_S3_SECRET_ACCESS_KEY}
Bucket ${OUT_S3_BUCKET}
S3Prefix apache
Region ap-northeast-1
fluentbitのStream Processorの処理フローの概要です。
分類されたログは、INPUTに戻り、再処理が行われる点のみ注意し設計しました。
https://docs.fluentbit.io/stream-processing/overview
なお、今回はservice属性の値をログ分類の判断基準としましたが
fluentd形式のJSONは、付加情報としてsource属性(stdout/stderr)を付与する為
標準出力とエラー出力の2種類の分類だけで良いのであれば
webコンテナから、service属性を出力する必要もないかと思います。
整形前
■ エラーログ
[0] f18902c94e19: [1573096151.000000000, {"container_name"=>"/firelens_web_1", "source"=>"stderr", "log"=>"{"service":"error.log", "message":"Exception."}", "container_id"=>"f18902c94e1916cf01fe986eee0e20d4c0ccbdd1bc419d1b122cc6fddd5b8522"}]
■アクセスログ
[1] f18902c94e19: [1573096151.000000000, {"container_id"=>"f18902c94e1916cf01fe986eee0e20d4c0ccbdd1bc419d1b122cc6fddd5b8522", "container_name"=>"/firelens_web_1", "source"=>"stdout", "log"=>"{"service":"access.log", "message":"172.19.0.1 - - [07/Nov/2019:03:09:11 +0000] GET /?exception HTTP/1.1 200 - - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36 6693"}"}]
整形後
■ エラーログ → datadogに送信される
{"container_name"=>"/firelens_web_1", "source"=>"stderr", "service":"error.log", "message":"Exception.", "container_id"=>"f18902c94e1916cf01fe986eee0e20d4c0ccbdd1bc419d1b122cc6fddd5b8522"}]
■ アクセスログ → S3に送信される
{"container_id"=>"f18902c94e1916cf01fe986eee0e20d4c0ccbdd1bc419d1b122cc6fddd5b8522", "container_name"=>"/firelens_web_1", "source"=>"stdout", service":"access.log", "message":"172.19.0.1 - - [07/Nov/2019:03:09:11 +0000] GET /?exception HTTP/1.1 200 - - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36 6693"}
実行
docker-compose up を実施し、http://localhost?exception にアクセスします。
fluentbitコンテナのログを確認すると、datadogへの転送が行われている事が確認できます。
21:24:45 datadog $docker logs -f e848ed87df3a0285bc82fb26a0796b00d00ddd443f14b2c0c5883d028c64dbea
Fluent Bit v1.3.0
Copyright (C) Treasure Data
[2019/11/09 12:24:30] [ info] [storage] initializing...
[2019/11/09 12:24:30] [ info] [storage] in-memory
[2019/11/09 12:24:30] [ info] [storage] normal synchronization mode, checksum disabled, max_chunks_up=128
[2019/11/09 12:24:30] [ info] [engine] started (pid=1)
[2019/11/09 12:24:30] [ info] [in_fw] binding 0.0.0.0:24224
[2019/11/09 12:24:30] [ info] [sp] stream processor started
[2019/11/09 12:24:30] [ info] [sp] registered task: access
[2019/11/09 12:24:30] [ info] [sp] registered task: ap
[2019/11/09 12:24:30] [ info] [sp] registered task: error
[2019/11/09 12:24:41] [ info] [out_datadog] https://http-intake.logs.datadoghq.com, port=443, HTTP status=200 payload={}
datadog logsを確認すると、エラーログを管理できていることを確認できます。
次回
以上で、ローカルの開発環境上で作成したfluentbitの構成ファイルの
動作確認を行う事ができました。
次回は、構成ファイルをfirelensと連携させ、fargate上での正常動作を確認していきます。