この記事で分かること
- ECSの標準のログ機能(
awslogs)で「何ができて、何ができないのか」。 - できないことを補う FireLens(Fluent Bit) がどんな仕組みなのか。
- 高負荷のときに「ログが消える」のはなぜか、どう備えるか。
はじめに:そもそも「ログ」って何?
アプリケーションは動いている間、「いま何をしているか」「エラーが起きた」といったメッセージを文字として出力します。これが ログ です。
プログラムが文字を出す場所は、主に次の2つです。
- 標準出力(stdout) — 通常のメッセージを出す場所
- 標準エラー出力(stderr) — エラーメッセージを出す場所
私たちがパソコンでプログラムを動かすと、これらは画面(ターミナル)に表示されます。
でも、AWS の ECS(コンテナを動かすサービス)の上でアプリを動かすと、画面はありません。ではログはどこへ行くのか? これを解決するのがこの記事のテーマです。
用語メモ
- コンテナ … アプリと、その動作に必要なものを1つの箱にまとめて、どこでも同じように動かせるようにした技術。
- ECS(Elastic Container Service) … AWS上でコンテナを動かしてくれるサービス。
- CloudWatch Logs … AWSの「ログの保管・閲覧サービス」。ログの最終的な置き場所としてよく使われる。
1. ECS標準のログ:awslogs ドライバ
ECSには、コンテナのログを CloudWatch Logs に送る標準機能があります。これを awslogs ドライバ と呼びます。
用語メモ:ログドライバとは?
コンテナが出したログ(stdout/stderr)を「どこへ・どうやって」運ぶかを決める仕組みのこと。
「ログの宅配業者」をイメージすると分かりやすいです。awslogsは「CloudWatch Logs 専門の宅配業者」です。
awslogs はとてもシンプルで、設定もかんたんです。
アプリのログ(stdout/stderr)
→ awslogsドライバ
→ CloudWatch Logs に届く
要件がシンプルなら、これで十分です。 わざわざ次に説明する FireLens を使う必要はありません。
でも、こんな要望が出てくると困る
プロジェクトが育つと、こんな声が出てきます。
- 「ログを CloudWatch だけでなく S3 にも 保存したい」
- 「ログを 外部の監視サービス(SaaS) にも送りたい」
- 「不要なログを 間引いて 料金を下げたい」
- 「ログにフィールドを足したり、JSONとして整形 したい」
- 「エラーのスタックトレース(複数行)を 1件のログにまとめたい」
awslogs は「CloudWatch Logs にそのまま送るだけ」なので、これらは一切できません。
送り先は固定、加工もできない。ここで登場するのが FireLens です。
2. FireLens とは何か(いちばん大事なところ)
初級者がまず誤解しやすいポイントです。
FireLens は「新しいログサービス」ではありません。
FireLens の正体は、次の2つを合わせた 仕組みの呼び名 です。
- Fluent Bit(または Fluentd)という、ログを集めて振り分けるソフトを動かす「サイドカーコンテナ」
- ECSが、その設定ファイルを自動で作ってくれる仕組み
用語メモ:サイドカーコンテナとは?
メインのアプリコンテナの「お供」として、同じタスク内で一緒に動く補助コンテナのこと。
バイクの横についている「サイドカー」が由来。ここでは「ログ集め係」のお供コンテナです。
用語メモ:Fluent Bit とは?
ログを「受け取って・加工して・いろんな宛先に振り分ける」ための軽量なソフト。
同種のソフトに Fluentd(Ruby製)もありますが、Fluent Bit は C言語製で軽くて速いため、ECSではこちらが主流です。
登場人物は3つ
FireLens を使うときに出てくる構成要素は、次の3つだけです。
| 登場人物 | 役割 | たとえ |
|---|---|---|
| アプリコンテナ | ログを出す本体 | 手紙を書く人 |
| ログルーターコンテナ(Fluent Bit のサイドカー) | ログを受け取り、振り分ける | 郵便局の仕分け係 |
| タスクIAMロール | 宛先に書き込む「権限」 | 宛先に入るための通行証 |
用語メモ:IAMロールとは?
AWSで「このリソースは、こういう操作をしてよい」という権限のまとまり。
ログを S3 や Firehose に送るには「送ってよい」という許可(権限)が必要です。これが無いと、いくら設定しても送れません。
3. ログはどんな道を通るのか(経路)
FireLens を使ったとき、ログは次のように流れます。
アプリのログ(stdout/stderr)
→ awsfirelens(ログドライバ)
→ ログルーターコンテナ(Fluent Bit)が受け取る
→ Fluent Bit が一時的にためる(バッファ)
→ 複数の宛先へ振り分け(CloudWatch / S3 / Firehose / 監視SaaS など)
ポイントは「ログルーター(仕分け係)がいったんログを受け取り、必要なら加工して、複数の宛先へ配る」という流れです。
awslogs(CloudWatch直行便)と違い、行き先を増やしたり加工したりできるのが分かります。
用語メモ:バッファとは?
受け取ったものを、すぐに送らずいったん貯めておく場所のこと。
宅配で言えば「集荷した荷物を、トラックが出発するまで置いておく倉庫」。
Fluent Bit はログを少しずつまとめて(chunk=かたまり、という単位で)宛先へ送ります。
おまけ:勝手に付くメタデータ
FireLens を使うと、各ログに「どのクラスタ・どのタスクから来たか」といった情報が自動で付きます。あとから「これはどのコンテナのログ?」と追跡しやすくなります。
| 付くキー | 内容 |
|---|---|
ecs_cluster |
クラスタ名 |
ecs_task_arn |
タスクの識別子(ARN) |
ecs_task_definition |
タスク定義名とリビジョン |
ec2_instance_id |
動いているEC2のID(※EC2起動タイプのときだけ。Fargateでは付かない) |
4. 高負荷のときに「ログが消える」のはなぜ?
FireLens 運用で最大の落とし穴がこれです。
大量のログが一気に流れると、ログが消えてしまうことがあります。 なぜでしょうか。
たとえ話:倉庫がパンクする
ログルーター(仕分け係)は、受け取ったログをいったん メモリ(作業机の上) にためてから宛先へ送ります。
- 普段はすぐ送れるので、机の上はすぐ片付く。
- でも、ログが大量に来たり、宛先が混んでいて送れないと、机の上に荷物がどんどん積み上がる。
-
机のスペース(
Mem_Buf_Limit)を超えると、新しい荷物を受け取れなくなり、あふれた分は捨てられます。 = ログ欠落。
Fluent Bit のログにはこんなメッセージが出ます。
[input] forward.1 paused (mem buf overlimit)
これは「メモリがいっぱいで受付を一時停止(pause)した」という意味です。pause している間のログは失われます。
さらに困ったことに、受付が止まるとアプリ側にも「ちょっと待って」という圧力(バックプレッシャー)がかかり、アプリの処理速度まで落ちることがあります。
用語メモ:メモリとディスクの違い
- メモリ : 速いけど消えやすい作業スペース(机の上)。コンテナが再起動すると中身は消える。
- ディスク(ファイルシステム) : 遅いけど消えにくい保管場所(引き出し)。再起動しても残る。
もうひとつの落とし穴:OOM(メモリ不足で強制終了)
宛先がダウンして送れない状態が続くと、メモリ上にログがたまり続けます。
やがてメモリを使い切ると、ログルーターコンテナが強制終了(OOMKill) され、メモリ上にあったログは丸ごと消えます。
用語メモ:OOM(Out Of Memory)とは?
「メモリが足りなくなった」状態。AWS/Linux はメモリを使いすぎたコンテナを強制終了して、システム全体を守ります。これを OOMKill と呼びます。
5. 解決策:メモリではなく「ディスク」にためる
ここまでの問題は、ほとんどが「メモリにためているから」起きています。
解決の方向性はシンプルで、ためる場所をメモリからディスク(ファイルシステム)に変えることです。
| メモリにためる(既定) | ディスクにためる(推奨) | |
|---|---|---|
| 速さ | 速い | やや遅い |
| 大量ログ | あふれると 欠落 | ディスクに退避できる |
| 宛先ダウン時 | メモリ枯渇 → OOMで全消失 | ディスクに貯めてゆるやかに耐える |
| 再起動時 | 消える | 残る |
つまり、本番環境ではディスク(ファイルシステム)バッファが推奨です。
設定イメージ(いまは「こういう設定を足すんだな」と眺めるだけでOK):
[SERVICE]
storage.path /var/log/flb-storage/ # ディスクにためる場所
storage.max_chunks_up 32 # メモリに置く量の上限(OOM防止)
storage.backlog.flush_on_shutdown On # 停止時に残りを送り切る
[INPUT]
Name forward
storage.type filesystem # ★ ここでディスクにためる指定
threaded true
[OUTPUT]
Name cloudwatch_logs
Match *
region us-west-2
log_group_name /aws/ecs/my-app
retry_limit 15 # 送信失敗時のリトライ回数
storage.total_limit_size 10G # ディスク使用の上限(超えたら古い順に破棄)
ポイントだけ言葉にすると:
-
storage.type filesystem… ログをディスクにためる(これが一番大事)。 -
storage.max_chunks_up… メモリに置く量を絞ってOOMを防ぐ。 -
retry_limit/storage.total_limit_size… 宛先が落ちても粘れるようにする。
出典
Amazon ECS で Fluent Bit のバッファ制限を構成する(公式の高スループット構成)
※storage.max_chunks_upでOOMを防ぐ考え方は、AWS公式サンプル oomkill-prevention も参考になります(いまは「公式にもお手本があるんだな」とだけ覚えておけばOK)。
注意
Mem_Buf_Limit(メモリの上限)を大きくするのは、あくまで一時しのぎです。
根本対策は「ディスクにためる」こと。一時回避と恒久対策は分けて考えましょう。
6. トラブルが起きたら、まずどこを見る?
「アプリのログが宛先に届かない!」というとき、まず確認する順番です。
確認の基本ステップ:
- ログルーターコンテナがちゃんと起動しているか(アプリより先に立ち上がる設定になっているか)。
- IAMロールに、宛先へ書き込む権限があるか(権限が無いとそもそも送れない)。
-
ログルーター自身のログに
paused/retry/ 権限エラーが出ていないか。 - 宛先側(CloudWatch や Firehose)が混雑(スロットリング)していないか。
大事な前提
FireLens/Fluent Bit には、AWS標準のCloudWatchメトリクスがありません。
だから「ログルーター自身のログ」を見られるように、ログルーターコンテナにもawslogsを設定して、自分のログをCloudWatchに出しておくのが鉄則です。これを忘れると、トラブル時に何も見えません。
7. セキュリティで1つだけ覚えておくこと
Fluent Bit はログを受け取るために、内部的に ポート24224 を使います。
このポート24224を、外部からアクセスできるように開けてはいけません。
同じタスク内のアプリから内部的に使われるだけなので、外(インターネットや他サーバー)に開放する必要はありません。セキュリティグループで ingress(外からの受信)を開けないのが正解です。
まとめ
-
awslogs… CloudWatch Logs に「そのまま送るだけ」の標準機能。シンプルな用途ならこれで十分。 - FireLens … 「複数の宛先に送りたい」「加工したい」「間引きたい」となったときに使う。正体は Fluent Bit のサイドカー + ECSの設定自動生成で、新しいサービスではない。
- ログの流れ … アプリ → ログルーター(Fluent Bit)→ いったんためる → 複数宛先へ。
- 高負荷でログが消えるのは、メモリにためていてあふれる(pause)か、メモリ不足で強制終了(OOM)するから。本番は ディスク(ファイルシステム)バッファ が推奨。
- トラブル時は ログルーター自身のログ を見る。そのためにログルーターにも
awslogsを仕込んでおくこと。 - ポート 24224 は外に開けない。
関連記事
- FireLensの挙動についての深掘り記事