とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

ECSでAWS FireLensを使ってみる

CloudWatch Logsにログを溜め込むのはコスト的に避けたいですよね。CloudWatch LogsにはS3にログをエクスポートする機能がるのですが、なぜか手動実行にしか対応していません。自動的にエクスポートするにはLambdaを定期実行するか、EventBridge Schedulerで定期的にエクスポートすることになります。

EventBridge SchedulerでS3にエクスポートするのがもっとも簡単な方法だと思うのですが、これには考慮する点があります。それはCloudWatch Logsの削除のタイミングとEventBridgeの実行のタイミングが同期していない点です。削除とエクスポートのタイミングで同期していないため、エクスポートより先に削除の処理が走るとその分ログが欠損します。そこで、保存期間よりもエクスポートを実行するタイミングを短く設定することで、エクスポートするログが被ってしまうのですが、安全に運用する方法があります。。。

と色々考えて面倒になってしまったので、S3とCloudWatch Logs両方に出力できるFireLensを使うことにします。

FireLens

aws.amazon.com

FireLensはFluentdやFluent Bitのフロントエンドとして動作します。FluentdやFluent BitではなくFireLensを使う利点は先のサイトにも書かれています。

Fluentd と FluentBit を使用して、ログをどこにでも簡単に送信する方法を必要としているユーザー。 Fluentd と FluentBit のフルパワーを必要としており、タスクのログをこれらのログルーターにパイプするために必要な差別化につながらない重労働は AWS に管理して欲しいユーザー。

FireLensを使うことでFluentdやFluent Bitの運用を気にすることなく、ログの転送先やログのフィルタに注力できます。

試す

docs.aws.amazon.com

ただ試すだけであれば、こちらに記載のタスク定義をECSにデプロイするだけで動作します。

軽く説明するとcontainerDefinitionsの1つ目の要素がFireLensのタスクです。

    {
            "name": "log_router",
            "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:stable",
            "cpu": 0,
            "memoryReservation": 51,
            "portMappings": [],
            "essential": true,
            "environment": [],
            "mountPoints": [],
            "volumesFrom": [],
            "user": "0",
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/ecs-aws-firelens-sidecar-container",
                    "mode": "non-blocking",
                    "awslogs-create-group": "true",
                    "max-buffer-size": "25m",
                    "awslogs-region": "us-east-1",
                    "awslogs-stream-prefix": "firelens"
                },
                "secretOptions": []
            },
            "systemControls": [],
            "firelensConfiguration": {
                "type": "fluentbit"
            }
    },

「logConfiguration」にはFireLens自体のログが「awslogs(CloudWatch Logs)」に出力されるように設定されています。「firelensConfiguration」でfluentbitを使用するように指定されています。

2つ目の要素にはデモアプリの設定が書かれています。

    {
      "essential": true,
      "image": "httpd",
      "name": "app",
      "logConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "firehose",
          "region": "us-west-2",
          "delivery_stream": "my-stream",
          "log-driver-buffer-limit": "2097152"
        }
      },
      "memoryReservation": 100
    }

こちらの「logConfiguration」では、「logDriver」に「awsfirelens」がセットされていますので、FireLensに出力されます。「options」にはFireLensがどこに出力するか指定します。今回の場合ですと、「us-west-2」にある「firehose」に出力するように指定されています。

このように、どこに出力するのかなどをタスク定義の中で完結できます。

※ロール・ポリシーに注意

  • FireLensのログをawslogsに出力するにはタスク実行ロール(execution_role)にログ出力の権限が必要です。Amazon ECS ログを CloudWatch に送信する - Amazon Elastic Container Service
  • FireLensがログを他のサービスに配信するにはタスクロール(task_role)にログ出力の権限が必要です。S3に配信するならs3:PutObject、CloudWatch Logsに配信するならlogs:PutLogEvents...etc

複数の出力先

FireLens(というかFluentdやFluent Bit)は複数の出力先を指定できます。が、タスク定義から設定できるのは1つの出力先だけです。複数の出力先を設定したい場合は設定ファイルを別途S3やコンテナ内に用意します。

FirelensConfiguration - Amazon Elastic Container Service

S3に置いておいて、起動時に読み込んでくれるなら、これはこれでいいのですが

Tasks hosted on AWS Fargate only support the file configuration file type.

Fargateには対応していないようです。悲しい・・・

と、諦めかけていたのですが、色々検索してみるとinit-プレフィックスのタグがあるコンテナは起動時にS3を確認してくれるそうで。ありがたや

GitHub - aws/aws-for-fluent-bit: The source of the amazon/aws-for-fluent-bit container image

使えるタグはこちらから確認できます。

https://gallery.ecr.aws/aws-observability/aws-for-fluent-bit

設定方法は以下の通り

    {
            "name": "log_router",
            "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:init-2.32.4",
            "cpu": 0,
            "memoryReservation": 50,
            "portMappings": [],
            "essential": true,
            "environment": [
                {
                    "name": "aws_fluent_bit_init_s3_1",
                    "value": "arn:aws:s3:::example-poc-fluent-bit-conf/extra.conf"
                }
            ],
            "mountPoints": [],
            "volumesFrom": [],
            "user": "0",
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "firelens-container",
                    "awslogs-create-group": "true",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "firelens"
                }
            },
            "systemControls": [],
            "firelensConfiguration": {
                "type": "fluentbit"
            }
        },

firelensのイメージを変更し、environmentで「aws_fluent_bit_init_s3_1」というキーにS3に置いてある設定ファイルまでのARNを指定しています。

S3に置いてあるextra.confは以下

[OUTPUT]
    Name cloudwatch_logs
    Match **
    region ap-northeast-1
    log_key log
    log_group_name firelens-container
    log_stream_prefix httpd/
    auto_create_group true

[OUTPUT]
    Name s3
    Match **
    bucket example-poc-ecs-logs
    region ap-northeast-1
    total_file_size 250M
    compression gzip
    s3_key_format /httpd/%Y/%m/%d/%H_%M.gz
    static_file_path On

appの内容は以下の通り

    {
            "name": "app",
            "image": "httpd",
            "cpu": 0,
            "memoryReservation": 100,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [],
            "mountPoints": [],
            "volumesFrom": [],
            "logConfiguration": {
                "logDriver": "awsfirelens"
            },
            "systemControls": []
        }

appは単に「logConfiguration」のoptionsを削除しました。

task_roleやexecution_roleの設定がうまくいっていてextra.confの置き場も間違いなければ、FireLensのタスクのログにはこのようなものが流れてきます。

設定が間違っているとAccess Deniedや403なども文字がでてくるでしょう。

コード

あーだこーだ書いたところでコードを見るのが1番理解が早いと思ったので、コードを用意しました。

github.com

こちらを実行するとAWSに動作環境一式が作成されます。

まとめ

AWSの公式ドキュメントではFargateはfileしか対応していないと書いてあって一瞬途方にくれましたが、aws-for-fluent-bitのREADME.mdにはinit-プレフィックスタグのコンテナだとS3からダウンロード可能というのを見つけられて大変助かりました。

FluentdやFluent Bitは慣れないとちょっと難しく感じるかもしれないですが、FireLensで簡単に導入できるので、まだ使ったことがない人は触ってみるといいかもしれません。