11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

S3更新時、CloudFrontのキャッシュを削除するLambdaをイベント通知で実行

Posted at

はじめに

S3とCloudFrontで静的サイトを構築した状態で、オリジンのS3が更新されたらCloudFrontのキャッシュを削除するLambdaを実装します。
キャッシュの削除は、全てのキャッシュを削除するパターンと、更新したファイルのキャッシュのみを削除するパターンの2パターンのコードを作成します。

スクリーンショット 2022-10-02 17.04.43.png

S3を作成

S3を作成します。
設定は以下の通りです。
スクリーンショット 2022-10-02 16.02.12.png

Cloudfront作成

設定は、以下以外は全てデフォルトです。

  • オリジンドメインは、先程作成したS3を選択
  • S3 バケットアクセスは、Origin access control settings (recommended)を選択
    • コントロール設定を作成する(設定はデフォルトでよい)
  • キャッシュポリシーは、開発中は、CachingDisabledにしておく
  • ビューワープロトコルポリシーは、Redirect HTTP to HTTPS
    スクリーンショット 2022-10-02 16.10.01.png
    スクリーンショット 2022-10-02 16.10.56.png
    ディストリビューション作成が成功すると、ポリシーをコピーし、S3のバケット権限に反映させましょう。
    スクリーンショット 2022-10-02 16.13.42.png

そして、s3に適当な画像をアップロードし、表示されるか確認しましょう。
aws-icon.png
スクリーンショット 2022-10-02 16.20.16.png
表示されることを確認しました。
スクリーンショット 2022-10-02 16.18.25.png

Lambdaを作成

Lambdaを作成します。Python3.9を指定し、他はデフォルトのままにします。
スクリーンショット 2022-10-02 17.11.04.png

IAMロール

LambdaのIAMロールにcloudfront:CreateInvalidationの権限をリソースを"arn:aws:cloudfront::xxxxxxxxxxx:distribution/*"に絞り、権限付与します。

xxxxxxxxxxxは、アカウントIDです。

修正前
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:ap-northeast-1:xxxxxxxxxxx:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:ap-northeast-1:xxxxxxxxxxx:log-group:/aws/lambda/delete-cache-of-cloud_front-in-S3:*"
            ]
        }
    ]
}
修正後
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "cloudfront:CreateInvalidation",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:cloudfront::xxxxxxxxxxx:distribution/*",
                "arn:aws:logs:ap-northeast-1:xxxxxxxxxxx:*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:ap-northeast-1:xxxxxxxxxxx:log-group:/aws/lambda/delete-cache-of-cloud_front-in-S3:*"
        }
    ]
}

コード

コードの内容ですが、S3の更新頻度によって2パターンに分かれると思います。

  1. S3の更新頻度が多い、または更新時のファイル数が多い場合
    • →1回の更新で、全キャッシュ削除します。
  2. S3の更新頻度が低い、または更新時のファイル数が少ない場合
    • → 更新ファイルごとに、そのパスのみのキャッシュを削除します

1.のパターンでは、パスごとに削除すると、Lambdaの実行回数が多く、同時実行数の上限に達したり、料金が高くなることがあります。
2.のパターンでは、パスごとに削除しても1.のデメリットがありません。また、削除する必要のないキャッシュは残るメリットがあります。

1.のパターンのコードはこちらです。
環境変数には、CloudFrontのディストリビューションIDをDISTRIBUTION_IDとして設定しています。

from __future__ import print_function
import boto3
import time
import os
import json

DISTRIBUTION_ID = os.environ['DISTRIBUTION_ID']

def decimal_to_int(obj):
    if isinstance(obj, Decimal):
        return int(obj)

def lambda_handler(event, context):
    print("Received event:" + json.dumps(event, default=decimal_to_int, ensure_ascii=False))
    
    client = boto3.client('cloudfront')
    invalidation = client.create_invalidation(DistributionId=DISTRIBUTION_ID,
        InvalidationBatch={
            'Paths': {
                'Quantity': 1,
                'Items': ['/*']
            },
        'CallerReference': str(time.time())
    })

開発中は、ログを残すため、printを使っていますが、本番時は削除してかまいません。

2.のパターンのコードはこちらです。

from __future__ import print_function
import boto3
import time
import os
import json

DISTRIBUTION_ID = os.environ['DISTRIBUTION_ID']

def decimal_to_int(obj):
    if isinstance(obj, Decimal):
        return int(obj)

def lambda_handler(event, context):
    print("Received event:" + json.dumps(event, default=decimal_to_int, ensure_ascii=False))
    
    for items in event["Records"]:
        path = "/" + items["s3"]["object"]["key"]
        print("path:" + path)
        client = boto3.client('cloudfront')
        invalidation = client.create_invalidation(DistributionId=DISTRIBUTION_ID,
            InvalidationBatch={
                'Paths': {
                    'Quantity': 1,
                    'Items': [path]
            },
            'CallerReference': str(time.time())
        })

S3のイベント通知でLambdaを指定

あとは、Lambdaのコンソール画面からトリガーを追加をクリックし、S3のイベント通知を設定します。
オプションのSuffixは、イベント通知する拡張子を指定できます。
スクリーンショット 2022-10-02 17.43.53.png

これで、S3にファイルをアップロードしたり、削除すると、Lambdaが起動し、cloudfrontのキャッシュを削除します。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?