ちょっと話題の記事

[アップデート] ECS/Fargateでログ出力先をカスタマイズできる「FireLens」機能がリリースされました

ECS/Fargateタスクのログ出力先をカスタマイズ (ルーティング) できる「FireLens」機能が正式リリースされましたので、試してみました。
2019.10.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさん、こんにちは!
AWS事業本部の青柳@福岡オフィスです。

ECS/Fargateタスクのログ出力先をカスタマイズ(ルーティング)できる「FireLens」機能が AWS Containers Roadmapリポジトリ でプレビューされていましたが、先日、正式リリースされました。

まだドキュメントが日本語化されていませんが、英語版ドキュメントの内容に沿って試してみました。 Custom Log Routing - Amazon ECS

従来の「CloudWatch Logs」へのログ出力

まず、従来の「CloudWatch Logs」へのログ出力を行ってみます。

全体の構成は下図のようになります。

ECSクラスターやALBの設定については省略します。(既に準備されているものとします)

アプリケーションコンテナ(今回はApache HTTP Server)を1つ含むタスク定義JSONファイルを以下のように記述します。

example-task-definition.json

{
    "family": "example-task-definition-20191001",
    "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
    "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "containerDefinitions": [
        {
            "name": "web-app",
            "image": "httpd:2.4",
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "entryPoint": [
                "sh",
                "-c"
            ],
            "command": [
                "/bin/sh -c \"echo 'FireLens Example' > /usr/local/apache2/htdocs/index.html && httpd-foreground\""
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/firelens-example",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "ecs"
                }
            }
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512"
}

logConfiguration にログ出力の設定を記述します。
logDriverawslogs を指定することで、ログ出力先をCloudWatch Logsに設定することができます。

タスク定義JSONファイルを使ってタスク定義を作成します。

$ aws ecs register-task-definition --cli-input-json file://example-task-definition.json

GUI (マネジメントコンソール) で設定する場合は以下のようになります。

このタスク定義を使ってサービスを作成し、タスクを起動すると、CloudWatch Logsにログが出力されることが確認できました。

「FireLens」を使ったログ出力

「FireLens」を使う場合の構成は下図のようになります。

CloudWatch Logへのログ出力のようにアプリケーションコンテナから直接ログをログ出力先に送信するのではなく、タスク内に「FireLensコンテナ」を追加して、FireLensコンテナ経由でログを送信する仕組みです。(いわゆる「サイドカー」構成ですね)

なお、上図ではログをKinesis Data Firehose経由でS3バケットへ出力していますが、これは一例で、FireLensは他にもCloudWatch LogやFluentdなどへのログ出力に対応しています。(今回は上図の通りKinesis Data Firehose経由でS3バケットへのログ出力を行います)

ログの出力先を準備する

ログの出力先となるKinesis Data FirehoseおよびS3バケットを作成します。(特別な設定は必要ないため手順は割愛します)

また、FireLensコンテナがKinesis Data Firehoseへストリームを送れるよう、タスクロールにアクセス権限を設定します。
(タスク実行ロールではなくタスクロールの方ですので注意してください)

タスクロール ecsTaskRole に以下のポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "firehose:PutRecordBatch",
            "Resource": "*"
        }
    ]
}

タスク定義を更新する

前項のタスク定義JSONファイルをコピーして、以下のように修正します。

example-task-definition-v2.json

{
    "family": "example-task-definition-20191001",
    "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
    "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "containerDefinitions": [
        {
            "name": "web-app",
            "image": "httpd:2.4",
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "entryPoint": [
                "sh",
                "-c"
            ],
            "command": [
                "/bin/sh -c \"echo 'FireLens Example' > /usr/local/apache2/htdocs/index.html && httpd-foreground\""
            ],
            "logConfiguration": {
                "logDriver":"awsfirelens",
                "options": {
                    "Name": "firehose",
                    "region": "ap-northeast-1",
                    "delivery_stream": "firelens-example-stream"
                }
            }
        },
        {
            "name": "log-router",
            "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
            "essential": true,
            "firelensConfiguration": {
                "type": "fluentbit"
            },
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/firelens-example",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "firelens"
                }
            }
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512"
}

34~49行目の記述で、FireLensコンテナの定義を追加しています。

        {
            "name": "log-router",
            "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
            "essential": true,
            "firelensConfiguration": {
                "type": "fluentbit"
            },
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/firelens-example",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "firelens"
                }
            }
        }

FireLensのコンテナイメージは、AWSが提供しているものを使用します。
これは、軽量ログ収集ツールである「Fluent bit」に、AWSが開発したプラグイン(Fluent bitからCloudWatch LogやKinesis Data Firehoseへ連係するためのプラグイン)を同梱したものになっています。

FireLensコンテナイメージのURLはリージョン毎に異なりますので、下記リンクを参照してください。
https://docs.aws.amazon.com/en_us/AmazonECS/latest/userguide/using_firelens.html#firelens-using-fluentbit

なお、FireLensコンテナの定義にも logConfiguration セクションがありますが、これはFireLensコンテナ自身の動作ログの出力先の設定になります。(CloudWatch Logsを指定しています)

続いて、既存のアプリケーションコンテナの定義について、ログ出力の設定を変更します。

            "logConfiguration": {
                "logDriver":"awsfirelens",
                "options": {
                    "Name": "firehose",
                    "region": "ap-northeast-1",
                    "delivery_stream": "firelens-example-stream"
                }
            }

26行目の logDriver の指定を awsfirelens に変更します。
また、28~30行目で、出力先を「firehose (=Kinesis Data Firehose)」にすること、および、Kinesis Data Firehoseに関する設定(リージョン、配信ストリーム名)を指定します。

タスク定義JSONファイルを修正しましたら、タスク定義の新しいリビジョンを作成します。

$ aws ecs register-task-definition --cli-input-json file://example-task-definition-v2.json

サービスの設定を更新し、タスク定義の新しいリビジョンでタスクを起動します。

現時点ではFireLensの設定をマネジメントコンソールから行うことはできません。
(ログドライバーの選択肢に「FireLens」が出てこない)

今回の手順のようにタスク定義をJSONファイルを使って作成する必要があります。

ログが出力されることを確認する

ログの最終送信先であるS3バケットを確認してみましょう。
年・月・日・時のフォルダが作成され、フォルダ内にログが格納されたことが確認できました。

S3バケットに格納されたログは、AWS GlueAmazon Athenaを使うとイイ感じに分析ができそうです。

おわりに

今回紹介したサンプルのみですと単にログ出力先をCloudWatchからKinesis Data Firehose/S3へ変更しただけということになりますが、FireLensには他にもいろいろな機能があります。

  • 正規表現によるログフィルタリング
  • 外部Fluentdへのログ転送

大量に動作するコンテナのログから必要なログのみを収集したり、1箇所に集めたログをツールで分析したり、ということに役立ちそうです。

AWSサービスへの対応がプラグインで提供されていたり、Fluent bitの設定をカスタマイズできたりと、今後の機能拡大にも期待です。