LambdaでCloudFrontのログをリネームしてみた

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

はじめに

AWSチームのすずきです。

AWSがCDNとして提供するCloudFront、そのアクセスログは任意のS3バケットに出力する事が可能です。

Amazon CloudFront » 開発者ガイド » アクセスログ

2014年11月のアップデートにより、CloudFrontがS3上に出力するアクセスログのファイル数は大きく減少しましたが、 一定の利用があるサイトでは、アクセスログとして出力されるログファイル数は1日数百に達するため、 ログの蓄積期間が長い場合、S3の特定パスに格納されているファイル数が多くなり、操作性に問題が出る場合がありました。

今回、S3イベントで起動するLambdaを利用し、ログファイルのキーに日付情報を付与するリネーム処理により、ログの操作性を改善する機会がありましたので、その内容について紹介をさせていただきます。

事前準備

  • CloudFront, S3のログ保管設定、Lambdaが利用するIAM設定を行います。

CloudFront

  • CloudFrontのログ設定、AWSコンソールのCloudFront画面より、確認、変更が可能です。

cflog-s3-lambda-01

  • 「Logbucket」が指定されていない場合、「Edit」より任意のS3バケットとログの有効化を行います。
  • 「Log Prefix」は、CloudFrontのDistribution毎に定義、CNAME、またはDistributionのDNS名とする事をおすすめします。

cflog-s3-lambda-02

S3設定

  • システムに求められるログ保持要件にあわせ、適切なライフルサイクル設定を行う事をお勧めします。

cflog-s3-lambda-03

IAMロール

  • Lambdaファンクションで利用するIAMポリシーを反映します

cflog-s3-lambda-04

cflog-s3-lambda-05

cflog-s3-lambda-06

cflog-s3-lambda-07

cflog-s3-lambda-08

cflog-s3-lambda-09

cflog-s3-lambda-10

cflog-s3-lambda-11

ポリシードキュメント

  • LambdaのBluePrint、S3アクセス用のサンプル「lambda_s3_exec_role」を元に、次の修正を実施して利用しました。
    • s3:DeleteObject 権限の追加
    • S3操作対象を限定するため、ResourceでS3バケットを指定
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::<ログ用S3バケット名>/*"
            ]
        }
    ]
}

設定

Lambda ファンクションの設置

  • Lambdaファンクションを設置します
  • ログ出力先のS3と同じリージョンにLambdaファンクションを設置します。

cflog-s3-lambda-12

  • Lambda のサンプルプログラムは指定せず、Skipします。

cflog-s3-lambda-13

  • 言語はPython 2.7を利用しました

cflog-s3-lambda-14

コードの反映

blueprintとして公開されている「s3-get-object-python」を元に、以下の修正を実施したコードを反映します。

  • 日付処理のため、「datetime」 をインポート
  • 新しいキー名(newkey)に、日付情報を付与
  • S3の高レベルAPI「copy_from」を利用し、日付を付与した新しいキーでコピーを実行
  • コピー完了後、旧ファイルは消去
from __future__ import print_function

import json
import urllib
import boto3
import datetime

print('Loading function')

s3 = boto3.resource('s3')

def lambda_handler(event, context):

    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')

    # Add Prefix datetime
    newkey = "archive-" + datetime.date.today().isoformat() + "/" + key

    try:
        response = s3.Object(bucket, newkey).copy_from(CopySource={'Bucket': bucket, 'Key': key})
        # print(response)

        response = s3.Object(bucket, key).delete()
        # print(response)

    except Exception as e:
        print(e)
        raise e
  • ロールは先に作成したLambda用ロールを指定します

cflog-s3-lambda-15

  • 設定内容を確認して、ファンクションを作成します。

cflog-s3-lambda-16

イベント登録

  • 「Event sources」タブより、「Add event source」を実施します。

cflog-s3-lambda-17

  • Event event source typeとして「S3」
  • BucketはCloudFrontのログ出力先を指定します
  • EventTypeは「Object Create」より「Put」を選択します
  • CloudFrontのログ設定に応じ「Prefix」を指定します

cflog-s3-lambda-18

動作確認

S3

  • Lambdaイベント設置後、CloudFrontのログは「/archive/(日付)/」に移動します。

cflog-s3-lambda-23

Lambda (Monitoring)

  • 過去24時間のLambdaの稼働状況が確認できます。
  • S3イベント設定変更後、設定不備で無限ループに陥っていない事を確認することをお勧めします。
  • より詳細な情報、前日以前のデータはCloudwatch画面にて確認可能です

cflog-s3-lambda-19

Invocations

  • 1時間に実行されたLambdaファンクションの実行回数が表示されます
  • CloudFrontが1時間に出力するログ件数と比較し、大きく乖離している場合Lambdaのイベント設定を確認します

Duration

  • 1時間に実行されたLambdaファンクションの実行のべ時間がmsで表示されます。

Errors

  • Lambdaファンクションが異常終了した件数が表示されます。
  • エラーが継続して発生している場合、該当時間の稼働ログ、後述のCloudwatchLogsで確認することをお勧めします

Throttles

  • 初期状態ではLambdaファンクションの同時実行数100に制限されており、その制限に触れた場合に表示されます。
  • S3イベントのLambdaは再実行が期待できないため、必要に応じログの手動移動を行います。
  • Throttlesが頻繁に発生する場合、上限緩和申請をAWSサポートに行います。

CloudwatchLogs

  • Lambdaファンクションの実行ログは、CloudwatchLogsで確認可能です。

cflog-s3-lambda-20

  • 今回のLambdaファンクション、1回の実行時間は400〜800ms、使用メモリは30MB前後、最小の128MBのメモリ指定で、リソース不足なく動作が確認できました。

cflog-s3-lambda-21

まとめ

S3上に出力されたログリネーム処理、BluePrintを雛形として簡単に実装する事ができました。

CloudFrontのログ解析方法については、以下のブログで紹介させて頂いていますが、 ログ保持期間が長く、対象となるファイル数が多い場合、日付情報による絞込が作業効率の向上に効果的です。

今回の利用したLambdaファンクション、1ヶ月の稼働させた環境の稼働実績は、リクエスト数は7000強、コンピューティング時間は約450GB/秒でした。 Lambdaには、1,000,000 件のリクエスト、および 400,000 GB/秒のコンピューティング時間の無料枠がありますが、この枠内での利用が可能でした。

cflog-s3-lambda-25

また、CloudFrontにかぎらず、S3のアクセスログなども同様に処理することが可能です。 ただし、S3に出力されるファイル数が極端に多い(毎秒100件超)場合、 Lambdaの同時実行数や、S3のキーがかたよる事によるパフォーマンス影響にもご注意ください。