S3 + Cloudfrontでサーバレスな感じを出す場合、S3にindex.htmlなりなんなりアップロードしたら、エッジサーバー上のキャッシュもクリアしてもらわないと困る。
ということで、S3にファイルをアップロードしたら、自動的にキャッシュクリアするようなLambdaを作成する。S3 -> LambdaのところはCloudformation使います。
仕組み
仕組みとしては、S3にファイルをアップロードしたら、それをLambdaが検知して、アップロードしたファイルのInvalidationをCloudFrontで実施する。中途半端にS3 -> LambdaのところだけCloudformation使う。
CloudFrontでディストリビューションを作成する
CloudFrontで適当にディストリビューションを作成する。コンソールから作った。オリジンの設定とかは適当。Distribution IDが知りたいだけ。
S3トリガのLambda用のファイルを作成する
S3にアップロードされたことをトリガにして、CloudFrontのInvalidationをするようなファイルを作成する。ここでは、s3/cfcache_clear.py というファイルを作成した。
"""S3にファイルがアップロードされたら 自動的にInvalidationする"""
import urllib.parse
import os
import time
import boto3
client_cf = boto3.client('cloudfront')
def lambda_handler(event, context):
"""S3にファイルがアップロードされたら起動する"""
# アップロードされたファイル
src_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
path = '/' + src_key
print(path)
# CloudFrontのキャッシュを削除する
response = client_cf.create_invalidation(
DistributionId=os.getenv('DISTRIBUTION_ID'),
InvalidationBatch={
'Paths': {
'Quantity': 1,
'Items': [path]
},
'CallerReference': str(time.time())
},
)
print(response)
DISTRIBUTION_IDを環境変数で持っている。
Cloudformation用のテンプレートファイルを作成してデプロイ
以下のようなtemplate.yamlを作成する。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
UpdateSourceProdFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: s3/
Environment:
Variables:
DISTRIBUTION_ID: ここにディストリビューションID
Handler: cfcache_clear.lambda_handler
MemorySize: 256
Role: arn:aws:iam::ほげほげ:role/ここにロール
Runtime: python3.7
Timeout: 5
Events:
UpdateSource:
Type: S3
Properties:
Bucket: !Ref SourceBucketProd
Events: s3:ObjectCreated:*
SourceBucketProd:
Type: AWS::S3::Bucket
Distribution IDはここで使う。
CloudFrontでInvalidationができるようなロールを作成しておく。CreateInvalidationが使えれば良いと思うが、ここではテストということで、最初から用意されているポリシーCloudFrontFullAccessを適用したロールを使った。
SourceBucketProdのところがバケット名になるので、わかりやすい名前にする。
設定ファイルを書いたら、デプロイする。ソース上げる用のバケットも作ろう。
aws s3 mb s3://<Bucket Name>
aws cloudformation package --template-file template.yaml --output-template-file template-output.yaml --s3-bucket <Bucket Name>
aws cloudformation deploy --template-file template-output.yaml --stack-name <Stack Name>
これで、仕組み自体は出来上がる。
確認する
aws s3 lsで作られたS3バケット名を確認したら、早速なにかファイルをアップロードしてみる。で、コンソールからCloudFrontを見にいって、Invalidationが実行されていればOK。
In Progress。OK。
参考記事
参考にさせていただきました。ありがとうございましたm(_ _)m
コメント