S3 + CloudFront で静的サイトを作成した。オリジンの S3 が更新されたら CloudFront のキャッシュを削除して、常に最新のファイルがキャッシュされている状態を作りたい。
はじめに
CloudFront にはキャッシュを明示的に削除する機能が存在していて、これを Invalidation という。
今回は S3 のバケットが更新されたら、更新されたパスに対応する CloudFront のキャッシュを Invalidate する Lambda Function を作って動かしてみようと思う。
事前調査
軽くググってみ他ところ同じような試みは多く、2016~2019年頃のいくつかの記事に目を通した。個々のファイルのキャッシュを削除するパターン、すべてのキャッシュを削除するパターン、S3の更新をトリガーにするパターン、定期的に削除するパターンなどがあった。
今回はファイルがアップロードされたら、対象のキャッシュだけを削除したいので、S3の更新をトリガーにして個別のキャッシュを削除する ようにする。
やること
- Lambda Function を作成する
- Invalidation を実行するコードをデプロイする
- Lambda から CloudFront へのアクセスを許可する
- S3 が更新されたら Lambda が動くようにする
Lambda の設定
Lambda Function を作成する
Lambda
>Functions
>Create function
- Author from scratch で1から作成する
- Runtime を Python 3.9 に設定
- 作成後、
Configuration
>Environment variables
で環境変数名DISTRIBUTION_ID
を作成してディストリビューションIDを設定しておく
Lambda から CloudFront にアクセスを許可する
Lambda
>Functions
> function_name >Configuration
>Permissions
を開く- Execution role 内の Role name をクリックして IAM を開く
- Permissions から Add permissions > Attach policies と進む
- CloudFront で検索して
CloudFrontFullAccess
にチェックしてAdd permissions
を押す
コードを書く
- 次のコードを Code source にペーストして
Deploy
を押す
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 Function が動くようにする
Lmabda
>Function overview
>+ Add trigger
と進み、設定画面へSelect a source
でS3 (aws storage)
を選択するBucket
でオリジンを指定- Event type は All object create events を指定して Add
動作確認
- 静的ファイルを更新したときに CloudFront 経由でも更新されているか確認する
- 上手くいっていないとき
- S3 上のファイルは更新されているか
- ログにエラーは出ていないか
CloudWatch のログイベント(成功した場合)
INIT_START Runtime Version: python:3.9.v19... START RequestId: .... Version: $LATEST Received evet: {"Records": ...} path: .... END RequestId: ... REPORT RequestID: ... Duration ...