🐈

ECS(Fargate)のnginxログをFireLensでs3へ転送する

2023/07/17に公開

はじめに

今回はECS(Fargate)で動かしているnginxのログをFireLensでs3へ転送してみたので、そのメモを記載します。

FireLensとはECSのログドライバの1つです。(他にはawslogs等がある)
実体はサイドカーでFluentBit or Fluentdコンテナが起動し、そのコンテナがログルーティングを行うといったものになっております。

https://aws.amazon.com/jp/blogs/news/under-the-hood-firelens-for-amazon-ecs-tasks/

イメージ図

検証

流れとしては

  • AWSリソース準備
  • Firehoseに書き込むためのタスクロール設定
  • タスク定義設定

となります。

AWSリソース準備

各種AWSリソースを用意します。
Firehoseに書き込むためのポリシーであったり、Firehose用のS3に書き込むためのポリシーであったり、IAM周りのリソース作成に注意しましょう。

Firehoseに書き込むためのタスクロール設定

タスクのfirelensコンテナがFirehoseに書き込むため、タスクロールを設定します。

⭕ タスクロール
❌ タスク実行ロール

です。混同しないように気をつけましょう。

タスクのポリシーは以下のようにしておけばOKです。

{
    "Statement": [
        {
            "Action": [
                "firehose:PutRecordBatch",
                "firehose:PutRecord"
            ],
            "Effect": "Allow",
            "Resource": "<deliverystream arn>",
            "Sid": ""
        }
    ],
    "Version": "2012-10-17"
}

タスク定義設定

FireLensを使用する場合のサンプルはこちらに記載があります。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/firelens-taskdef.html

[
    {
      "name": "nginx",
      "image": "nginx:latest",
      // 略
      "LogConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "firehose",
          "region": "ap-northeast-1",
          "delivery_stream": "my-firehose-stream"
        }
      }
    },
    {
      "essential": true,
      "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable",
      "name": "log_router",
      "firelensConfiguration": {
          "type": "fluentbit"
      },
      "logConfiguration": {
          "logDriver": "awslogs",
          "options": {
              "awslogs-group": "/ecs/logs/firelens",
              "awslogs-region": "ap-northeast-1",
              "awslogs-stream-prefix": "firelens"
          }
      },
      "memoryReservation": 50
  }
]

ポイントは以下です。

  • ログを飛ばしたいコンテナで "logDriver": "awsfirelens"を設定する
  • firelens用のコンテナを追加する
    • firelens自体のログはcloudwatch logsに保存する
  • 今回はfluentbitを使用するため、firelensConfigurationで指定する。

動作確認①

問題なければs3にログが飛びます。
年月日で階層化されて、delivery_stream名-<ランダム文字列>というフォーマットで定期的に出力されるようです。

s3bucket/
└── yyyy
    └── mm
        └── dd
            └── hh
                └── logfile

動作確認②

firehoseのdelivery_streamのメトリクスも確認してみます。
特に問題はなさそうです。

動作確認③

ファイルの中身を確認します。
curl -Iでリクエストを投げたところ、このようなログで記録されていました。
FluentBit形式のログになっているようです。

{"container_id":"<コンテナランタイム ID>","container_name":"<コンテナ名>","ecs_cluster":"<ECSクラスタ>","ecs_task_arn":"<ECSタスクARN>","ecs_task_definition":"<タスク定義名>","log":"10.10.2.75 - - [17/Jul/2023:08:37:02 +0000] \"HEAD / HTTP/1.1\" 200 0 \"-\" \"curl/7.81.0\" \"<グローバルIP>\"","source":"stdout"}
  • container_id:コンテナランタイムID
  • container_name:コンテナ名
  • ecs_cluster:ECSクラスタ名
  • ecs_task_arn:ECSタスクARN
  • ecs_task_definition:タスク定義名
  • log:nginxが吐いたログ。プライベートIPはALBのもの
  • source:不明なので今度調べる。おそらくコンテナの標準出力であることを表している。

なにはともあれ、このようにFirelens経由でログがs3に吐かれていることが確認出来ました!

ハマったメモ

① コンテナ定義でnameと指定する

このようなログが出力され、タスクが起動しませんでした。

InternalError: unable to generate fireLens config file: unable to generate fireLens config content: unable to generate fluent config output section: unable to apply log options of container nginx to fireLens config: missing output key Name which is required for fireLens configuration of type fluentbit. Launch a new task to retry.

コンテナ定義でのFirelens設定を確認すると

container-definisions.json
      "LogConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "name": "firehose",
          "region": "ap-northeast-1",
          "delivery_stream": "xxxxxxxxxxx"
        }
      }

となっていました。
正しくは

container-definisions.json
      "LogConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
-          "name": "firehose",
+          "Name": "firehose",
          "region": "ap-northeast-1",
          "delivery_stream": "xxxxxxxxxxx"
        }
      }

なので注意しましょう。
他のオプションが小文字であるため、混同してしまう可能性はありそうです。

https://ebc-2in2crc.hatenablog.jp/entry/2020/08/08/161034

② Firehoseへログを書き込む権限が足りない

このようなログがfirelensサイドカーから出てきたらログ転送先への書き込み権限が足りていません。
タスクロール、ポリシーを適切に設定することで対応しましょう。

time="2023-07-17T07:44:25Z" level=error msg="[firehose 0] PutRecordBatch failed with AccessDeniedException: <taskrole arn> is not authorized to perform: firehose:PutRecordBatch on resource: <firehose-stream> because no identity-based policy allows the firehose:PutRecordBatch action\n\tstatus code: 400, request id: xxxyyyzzz123

こちらにサンプルを記載しています。

おわりに

次は複数の宛先にログルーティングするやり方を調査したいと思います。

参考

https://zenn.dev/mpyw/scraps/5c299399a6d8be
https://aws.amazon.com/jp/blogs/news/announcing-firelens-a-new-way-to-manage-container-logs/

Discussion