dshimizu/blog/alpha

とりとめのないITブログ

AWS Firgate タスクのログを FireLens と Fluent Bit S3 Plugin, CloudWatch Logs plugin を使ってログを保存する

はじめに

AWS Firgate タスクのログについて、どのように管理して行くか検討したい点はいくつかあります。

  • 保存先をどこにするか
    • CloudWatch Logs, S3, 外部...
  • どの程度の期間保存するか
  • アラート通知をどうするか

概ね、以下のような形にはしたいですが、料金や要件等によって変わってくるところもあるかなと思います。

  • S3: 出力される全てのログを保存し、長期間保存する (場合によっては Glacier へ保存する)
  • 外部監視ツール
  • CloudWatch Logs: アラームを出したいログ、Insightで見たい内容、または直近1ヶ月分等の短い期間のログ全量または一部

ログ送信先

ログの量が増え、保存期間が長くなるほど CloudWatch Logs よりは S3 に保存する方がコスト面では有利かと思います。

  • 料金 - Amazon CloudWatch | AWS

    収集 (データの取り込み): 0.50USD/GB \

    保存 (アーカイブ): 0.03USD/GB \

    分析 (Logs Insights のクエリ): スキャンしたデータ 1 GB あたり 0.005USD \

    検出およびマスク (データ保護): スキャンされたデータ 1 GB あたり 0.12USD \

    分析 (Live Tail): 0.01 USD/分 \

  • 料金 - Amazon S3 |AWS

    S3 標準 - 頻繁にアクセスするデータに一般的に使用される、あらゆるタイプのデータの汎用ストレージ

    最初の 50 TB/月 0.025USD/GB \

    次の 450 TB/月 0.024USD/GB \

    500 TB/月以上 0.023USD/GB \

    インターネットから Amazon S3 へのデータ転送受信 (イン) \

    すべてのデータ受信 0.00USD/GB

    Amazon S3 からインターネットへのデータ転送送信 (アウト) \

    最初の 10 TB/月 0.114USD/GB \

    次の 40 TB/月 0.089USD/GB \

    次の 100 TB/月 0.086USD/GB \

    150 TB/月以上 0.084USD/GB \

    PUT、COPY、POST、LIST リクエスト (1,000 リクエストあたり) GET、SELECT、他のすべてのリクエスト (1,000 リクエストあたり) ライフサイクル移行リクエスト (入) (1,000 件のリクエストあたり) データ取り出しリクエスト (1,000 リクエストあたり) データ取り出し (GB あたり) \

    S3 標準 0.0047USD 0.00037USD 該当なし 該当なし 該当なし

リアルタイムに確認したい場合は CloudWatch Logs の方がやりやすいかもしれません。

ログ保存に使うツール

Fargate または ECS だと、ログの送信先を複数にする場合は、サイドカーコンテナで firelens を準備して、 firelens から複数の場所へ送信する場合が多いと思います。 単独なら awslogs ログドライバーを使って CloudWatch Logs へ出力し、そこから何かしらで別な場所へ取り込む形になると思います。

Fluentbit を使って S3 にログを送る場合、 firehose プラグインを使って firehose -> S3 とする方法と、 S3 プラグインを使って S3 へ直接ログを送る方法があるかと思います。

S3プラグインを使うと一発でS3へログを出力できて便利ですが、Fluentbitがリアルタイムにログデータを送るので、firehose をかました方が良いかもしれません。 ここではS3プラグインを使って直接S3へログを書き込む形にしています。

FireLens

FireLens は、Fluent Bit または Fluentd と組み合わせて動作する、ECS タスクログを転送するためのツールであるようです。 Fluent Bit または Fluentd をログルーターサイドカーコンテナとして起動させておき、ECS タスクのログを標準出力と標準エラー出力を、AWS FireLens ログルーターサイドカーコンテナへ転送し、ログを受け取ったログルーターコンテナが Fluent Bit または Fluentd の設定に従って、 CloudWatch logsやS3、DataDog といったAWS内外のサービスへログを出力してくれます。 そのため、アプリケーション側でログ出力以外に特別な対応は必要ありません。

FireLens ではログルーターOSS である Fluent Bit または Fluentd を選択できるようですが、AWSではより軽量である Fluent Bit が推奨されています。 AWS for Fluent Bit のコンテナイメージも公開されています。

設定例

Fluentbit を使って AWS Fargate のログを CloudWatch Logs, S3 へ送ってみます。 使うのは CloudWatch Logs プラグインと S3 プラグインです。

環境

  • AWS Fargete
  • Fluentbit (AWS for Fluent Bit v2.32.0)

Fluentbit 設定ファイル

extra.conf を以下のような内容で記述します。ログ全量をCloudWatch LogsとS3へ出力するようにしています。必要に応じてフィルターを設定します。

[OUTPUT]
    Name cloudwatch_logs
    Match *
    region ap-northeast-1
    log_group_name /ecs/${ENV}-sandbox-ecs-fargate-service/task/app
    log_stream_prefix fluentbit-
    log_key log

[OUTPUT]
    Name s3
    Match *
    region ap-northeast-1
    bucket test-bucket
    total_file_size 1M
    upload_timeout 1m
    use_put_object On

Fluentbit Docker ファイル

以下のような形にします。

FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:2.32.0
COPY ./extra.conf /fluent-bit/etc/extra.conf

タスクロール

Fargete タスクが S3 と CloudWatch Logs へアクセスできるように必要な権限を定義したタスクロールを作成します。 以下のようなタスクロールを作成します。結構雑ですがより厳密にやる場合はResourseセクションをきちんと指定するなどが必要です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CloudWatchLogsPermissions",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream",
                "logs:CreateLogGroup",
                "logs:DescribeLogStreams"
            ],
            "Resource": "*"
        },
        {
            "Sid": "S3Permission",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:PutObject"
            ],
            "Resource": "*"
        }
    ]
}

タスク定義

タスク定義を以下のような形します。

主には以下のような項目の設定が必要になると思います。

  • メインのコンテナ(ここでは app)の logConfiguration"logDriver": "awsfirelens" を設定します。
  • サイドカーとなるコンテナ(ここでは log-router )で firelensConfiguration を設定します。
  • 環境変数の項目では、 extra.conf で必要なものを記述します。ここでは ${ENV} のみとしています
{
  "containerDefinitions": [
    {
      "command": [],
      "cpu": 0,
      "essential": true,
      "image": "nginx",
      "logConfiguration": {
        "logDriver": "awsfirelens"
      },
      "name": "web",
      "portMappings": [
          {
              "name": "nginx-80-tcp",
              "containerPort": 80,
              "hostPort": 80,
              "protocol": "tcp",
              "appProtocol": "http"
          }
      ],
    },
    {
      "cpu": 0,
      "essential": true,
      "firelensConfiguration": {
        "options": {
          "config-file-type": "file",
          "config-file-value": "/fluent-bit/etc/extra.conf",
          "enable-ecs-log-metadata": "true"
        },
        "type": "fluentbit"
      },
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/log-router:latest",
      "memoryReservation": 50,
      "name": "log-router",
      "environment": [
        {
          "name": "ENV",
          "value": "dev"
        }
      ]
      "user": "0"
    }
  ],
  "family": "dev-sandbox-ecs-fargate-taskdef",
  "taskRoleArn": "arn:aws:iam::123456789012:role/dev-sandbox-ecs-task-role",
  "executionRoleArn": "arn:aws:iam::123456789012:role/dev-sandbox-ecs-task-exec-role",
  "networkMode": "awsvpc"
}

ビルド&デプロイ

メインのコンテナとサイドカーコンテナをECRへプッシュし、Fargateへデプロイします。 ここでは詳細なやり方は割愛します。

確認

CloudWatch Logs と S3 へログが出ていることを確認します。

まとめ

AWS Firgate タスクのログ管理について、S3と CloudWatch Logsへ保存する場合と、それをやる場合のサンプルについて書きました。

参考