概要
今回は、EC2で稼働している弊社のアプリケーションログをCloudWatch Logsへ集約しました。
その中で調査したツールの比較や、設定方法について紹介します。
背景
弊社の主要なアプリケーションは2台のEC2で稼働しています。
これまではエラーを調査する際、
- EC2(A)にsshで接続してログファイルをgrepして探し、
- 該当エラーがない場合はEC2(B)にsshして...
とそれぞれのインスタンスを行き来することになり、調査に時間がかかっていました。
そこで、アプリケーションログをCloudWatch Logsに集約することでログを一元管理し、ブラウザからエラー調査ができるようにする必要がありました。
各ツールの比較
FireLens
ECSの場合使用可能。今回は通常のEC2なので候補から外れました。
なぜ単に Fluentd や Fluent Bit を推奨しないのですか?なぜ FireLens なのですか?
Fluentd と Fluent Bit は強力ですが、たくさんの機能セットには常に複雑さが伴います。FireLens を設計する際、2 つの主要なユーザーセグメントを想定しました。
- Fluentd と FluentBit を使用して、ログをどこにでも簡単に送信する方法を必要としているユーザー。
- Fluentd と FluentBit のフルパワーを必要としており、タスクのログをこれらのログルーターにパイプするために必要な差別化につながらない重労働は AWS に管理して欲しいユーザー。
最初のグループに対する私たちの答えは、私たちが作成した FireLens サンプルの GitHub リポジトリによって最もよく実証されています。これらの例のほとんどは、タスク定義での設定のみを必要とし、誰でもわずかな変更だけで使用することができます。簡単であり、Fluentd や Fluent Bit の知識を必要としません。2 番目のグループに対する私たちのソリューションは、タスク定義の FireLensConfiguration オブジェクトの options フィールドに示されています。
このように、ECSを利用している場合は後述のFluentdやFluent Bitよりも推奨されています。
FireLensを利用することで内部的にFluentdやFluent Bitが使用できます。
利点としては、設定ファイルをS3から読み込めるので、設定ファイルをイメージに含める必要がなくなるようです。
Fluentd vs Fluent Bit
それぞれ以下のような違いがあります。
拡張性を持たせたい場合はFluentdに軍配が上がりますが、そうでない場合はFluent Bitが良さそうです。
Fluentd | Fluent Bit | |
---|---|---|
対応 | コンテナ/サーバー | コンテナ/サーバー/組み込みLinux |
言語 | C、Ruby | C |
メモリ | 60MB以上 | 1MB以下 |
パフォーマンス | 中 | ハイパフォーマンス |
依存関係 | Ruby Gemとして構築されているので、一定数のGemが必要 | 基本なし |
プラグイン | 1000以上 | 100以上 |
ライセンス | Apacheライセンスv2.0 | Apacheライセンスv2.0 |
参考: https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit
AWSからも推奨されているようですね。
Fluent Bit が AWS の推奨ですが、それは Fluentd に比べてリソース使用量が大幅に少ないからです。Fluentd も何百ものプラグインが存在する定評のあるツールであり、サポートします。長期的には、FireLens がオープンソースコミュニティを活性化し、Fluentd がサポートする多くの機能とすべての送信先が Fluent Bit に追加されることを期待しています。AWS は Fluent Bit にプラグインや改善を提供し続けることで、この役割を果たしていきます。
今回のユースケースにはどちらが合うか
Fluent Bitを使用することにしました。
理由としては、
- 今回は、単純にログをCloudWatch Logsに出力できればよかった
- より軽量でハイパフォーマンス
- 外部依存がない
からです。
その他の理由として、Container InsightsではFluentdは非推奨になりつつあることも挙げられます。
将来的にEC2→ECSに移行する可能性もあるため、Fluent Bitの方がより安全策とも言えますね。
Container Insights の Fluentd のサポートは現在メンテナンスモードになっています。つまり、AWS はこれ以上 Fluentd の更新を提供せず、近い将来に廃止する予定です。
さらに、Container Insights の現在の Fluentd 構成は、最新の改善およびセキュリティパッチがない古いバージョンの Fluentd Imagefluent/fluentd-kubernetes-daemonset:v1.10.3-debian-cloudwatch-1.0
を使用しています。
設定方法
ここからは具体的な設定方法を紹介します。
以下の資料を参考にしています。
1. EC2のOSを確認する
まずは、Fluent BitをインストールするEC2のOSを確認します。
EC2上で、以下のコマンドを実行することで確認できます。
$ cat /etc/os-release
OSはubuntuでした。
2. Fluent Bitをインストールする
こちらから対応しているものを選択します。
今回はhttps://docs.fluentbit.io/manual/installation/linux/ubuntu を使用しました。
// fluent-bitをインストール
$ curl https://raw.githubusercontent.com/fluent/fluent-bit/master/install.sh | sh
// 有効化
$ sudo systemctl start fluent-bit
// ステータスの確認
$ systemctl status fluent-bit
● fluent-bit.service - Fluent Bit
Loaded: loaded (/lib/systemd/system/fluent-bit.service; disabled; vendor preset: enabled)
Active: active (running) since 水 2024-02-28 08:49:34 UTC; 1min 11s ago
Docs: https://docs.fluentbit.io/manual/
Main PID: 32313 (fluent-bit)
Tasks: 4
Memory: 13.2M
CPU: 53ms
CGroup: /system.slice/fluent-bit.service
└─32313 /opt/fluent-bit/bin/fluent-bit -c //etc/fluent-bit/fluent-bit.conf
この時点では、ログはsudo tail -f /var/log/syslogで確認できます。
デフォルトでは1秒ごとにcpuのログが吐かれ続けるので、一旦止めておきます。
$ sudo systemctl stop fluent-bit
3. 出力先をCloudWatch Logsに変更
上記出力より、設定は/etc/fluent-bit/fluent-bit.confを見ていることが分かります。
このファイルを編集し、各アプリおよびnginxのログの設定をします。
以下は設定の例です。
各設定の意味は後述します。
[INPUT]
Name tail
Path /var/log/hogehoge/app_A/stdout.log
Tag app_A.log
[INPUT]
Name tail
Path /var/log/hogehoge/app_B/stdout.log
Tag app_B.log
[INPUT]
Name tail
Path /var/log/hogehoge/nginx/access.log
Tag nginx.access_log
[INPUT]
Name tail
Path /var/log/hogehoge/nginx/error.log
Tag nginx.error_log
[OUTPUT]
name cloudwatch_logs
match app_A.log
region ap-northeast-1
log_group_name /aws/ec2/app_A
log_stream_name ${EC2_TAG_NAME}-${APP_A_DEPLOY_DATETIME}
auto_create_group true
workers 1
log_retention_days 3
log_key log
[OUTPUT]
name cloudwatch_logs
match app_B.log
region ap-northeast-1
log_group_name /aws/ec2/app_B
log_stream_name ${EC2_TAG_NAME}-${APP_B_DEPLOY_DATETIME}
auto_create_group true
workers 1
log_retention_days 3
log_key log
[OUTPUT]
name cloudwatch_logs
match nginx.*
region ap-northeast-1
log_group_name /aws/ec2/nginx
log_stream_prefix ${EC2_TAG_NAME}-
auto_create_group true
workers 1
log_retention_days 3
log_key log
4. configファイルをアプリごとに分離する
/path/to/fluent-bit-app_A.conf
[INPUT]
Name tail
Path /var/log/hogehoge/app_A/stdout.log
Tag app_A.log
[OUTPUT]
name cloudwatch_logs
match app_A.log
region ap-northeast-1
log_group_name /aws/ec2/app_A
log_stream_name ${EC2_TAG_NAME}-${APP_A_DEPLOY_DATETIME}
auto_create_group true
workers 1
log_retention_days 3
log_key log
/path/to/fluent-bit-app_B.conf
[INPUT]
Name tail
Path /var/log/hogehoge/app_B/stdout.log
Tag app_B.log
[OUTPUT]
name cloudwatch_logs
match app_B.log
region ap-northeast-1
log_group_name /aws/ec2/app_B
log_stream_name ${EC2_TAG_NAME}-${APP_B_DEPLOY_DATETIME}
auto_create_group true
workers 1
log_retention_days 3
log_key log
/path/to/fluent-bit-nginx.conf
[INPUT]
Name tail
Path /var/log/hogehoge/nginx/access.log
Tag nginx.access_log
[INPUT]
Name tail
Path /var/log/hogehoge/nginx/error.log
Tag nginx.error_log
[OUTPUT]
name cloudwatch_logs
match nginx.*
region ap-northeast-1
log_group_name /aws/ec2/nginx
log_stream_prefix ${EC2_TAG_NAME}-
auto_create_group true
workers 1
log_retention_days 3
log_key log
上記のconfファイルを以下のように読み込みます。
@INCLUDE /path/to/fluent-bit-wk_web.conf
@INCLUDE /path/to/fluent-bit-wvd_userui.co
@INCLUDE /path/to/fluent-bit-nginx.conf
各設定項目について
[INPUT]
// tail -fコマンドのように、ファイル末尾をログとして吐く
Name tail
// ソースとなるログファイル
Path /var/log/supervisor/vk_web/stdout.log
// タグ名。[OUTPUT]へのルーティングのために使用する。
Tag vk_web.log
[OUTPUT]
// ログ出力先にcloudwatch_logsを指定
name cloudwatch_logs
// [INPUT]のうち、Tagが一致するものをこのOUTPUTにルーティングする。ワイルドカード指定もできる。
match vk_web.log
// リージョン指定
region ap-northeast-1
// ロググループ名
log_group_name /aws/ec2/vk_web
// ログストリーム名(詳細は後述)
log_stream_name ${EC2_TAG_NAME}-${VK_WEB_DEPLOY_DATETIME}
// trueの場合、ロググループを自動的に作成する
auto_create_group true
// cloudwatchへの出力用にスレッドを確保する。ほとんどの場合0か1で問題ない
workers 1
// ログストリームの保持日数
log_retention_days 3
// fluent-bitの出力のうちcloudwatchに送るkeyを指定、logの場合は純粋なログのみ出力する
log_key log
上記のうち、log_stream_nameでは${EC2_TAG_NAME}-${VK_WEB_DEPLOY_DATETIME}
のように${}
のフォーマットで環境変数を読み込んでいます。
5. 環境変数の設定
Fluent Bitは、環境変数をwebサーバー上の/etc/default/fluent-bit
から読み込みます。
今回の記事からは省略しますが、
Github Actionsの中でshellを実行し、環境変数としてデプロイ日時を設定することで
デプロイごとにログストリームが分かれるようにしています。
コストの考慮
ログの保存にも以下のようにお金がかかります。
基本的にログ調査は、当日や土日に起こったエラーの調査をすることがほとんどであり、
最悪元々のようにEC2にsshしてログファイルを直接確認することもできます。
よって、ログの保持期間は3日と設定しています。
収集 (データの取り込み)・・・0.50USD/GB
保存 (アーカイブ)・・・0.03USD/GB
分析 (Logs Insights のクエリ)・・・スキャンしたデータ 1 GB あたり 0.005USD
検出およびマスク (データ保護)・・・スキャンされたデータ 1 GB あたり 0.12USD
分析 (Live Tail)・・・0.01 USD/分
完了!
変更した設定を読み込ませるために、Fluent Bitを再起動させます。
$ sudo systemctl restart fluent-bit
アプリケーションへのアクセスがあった時、
auto_create_group true
としているためロググループ、ログストリームが存在しなければ自動生成してくれます。
まとめ
Fluent Bitが自動でロググループやログストリームを生成してくれるのには感動しました。
今後ログ調査環境を整える際は、ぜひ使用を検討してみてください!