2021年08月27日
S3 同期の際に Lambda で自動的に CloudFront のキャッシュをパージする
前回は、lsyncd を使ってコンテンツを S3 に同期する仕組みを構築する例 をご紹介しました。これにより、EC2 インスタンスで行われた更新を Amazon CloudFront のオリジンとなる S3 に同期することができるようになりますが、更新を反映するためには Amazon CloudFront のキャッシュをパージする必要があります。今回は、これを Lambda を使って自動的に行う方法をご紹介します。
前提
すでに S3 をオリジンとした CloudFront が稼働中の状態を想定しています。キャッシュのパージに一日あたりの上限を設けつつ、パージ実行のタイミングを明確にするため、(最上位階層かサブフォルダ内かに関わらず)特定の名前のファイルが更新された場合のみパージを行うものとします。
CloudFront ディストリビューションの ID を確認する
コンソールから、[CloudFront] > [Distributions] を表示した際の一覧の ID 列です。後述の手順で使うので、メモしておきましょう。
キャッシュパージの回数を記録するための S3 バケットを作成する
コンソールから、[Amazon S3] > [バケット作成] から作成します。ここではバケット名を「limited-cf-purge-by-file-countup」としました。バケット名以外はデフォルトのまま [バケットを作成] ボタンを押します。
Lambda 関数の作成
新しい関数を作成します。関数名はここでは「limited-cloudfront-purge-by-file」とし、ランタイムに「Python 3.8」を指定します。他の項目はデフォルトのまま [関数を作成] ボタンを押します。
関数が作成されたら、コードソースに下記をコピー&ペーストします。DISTRIBUTION_ID
, ORIGIN_BUCKET_NAME
, COUNT_BUCKET_NAME
をご利用環境に合わせて変更してください。また、ここでは、ファイル名が「.purge」のファイルに変更があったら、一日に 10 回までキャッシュのパージを行う設定になっています。状況に合わせて COUNT_MAX
, TARGET_FILE
を変更してください。
また、念のため、CloudWatch Logs に記録するための print を入れています。
import boto3
import time
import re
from botocore.errorfactory import ClientError
from datetime import datetime
DISTRIBUTION_ID = 'CloudFront の ID'
ORIGIN_BUCKET_NAME = 'オリジンである S3 バケットの名前'
COUNT_BUCKET_NAME = 'パージ回数を記録する S3 バケットの名前'
COUNT_MAX = 10
TARGET_FILE = '.purge'
pattern = '(?:\A|\/)' + TARGET_FILE + '$'
compiled = re.compile(pattern)
def lambda_handler(event, context):
s3 = boto3.resource('s3')
key = datetime.now().strftime('%Y-%m-%d') + '.txt'
object = s3.Object(COUNT_BUCKET_NAME, key)
try:
response = object.get()
body = response['Body'].read()
count = int(body)
except ClientError:
count=0
print(count)
if count < COUNT_MAX:
print('NOT MAX')
for items in event["Records"]:
if items["s3"]["bucket"]["name"] == ORIGIN_BUCKET_NAME:
if compiled.search(items["s3"]["object"]["key"]):
print('FILENAME PATTERN MATCHED')
client = boto3.client('cloudfront')
invalidation = client.create_invalidation(
DistributionId=DISTRIBUTION_ID,
InvalidationBatch={
'Paths': {
'Quantity': 1,
'Items': ['/*']
},
'CallerReference': str(time.time())
})
print('INVALIDATION CREATED')
count+=1
break
else:
print('IS MAX')
return
object.put( Body=str(count) )
return
パージ回数を記録するバケットには、「2021-08-06.txt」のように、日付ごとにファイルを作成し、内容としてパージ回数が記録していきます。月ごとにする場合は、'%Y-%m-%d'
の部分を '%Y-%m'
にしてください。合わせて COUNT_MAX
も増やしたほうがいいかもしれません。
※ このコードでは日付が UTC となりますが、内容の簡略化のため、JST にする方法はここでは触れません
コードソースの編集が終わったら、[Deploy] ボタンを押してデプロイします。このまま実行すると権限周りでエラーになるので、S3 と CloudFront に対する権限の設定と、オリジンである S3 の更新をトリガーとして関数を実行するための設定を行います。
アクセス権限の設定
[設定] > [アクセス権限] > [実行ロール] に表示されているロール名を選択し、ロールの編集画面を表示します。
[アクセス権限] タブの [ポリシーをアタッチします] から、「AmazonS3FullAccess」「CloudFrontFullAccess」を追加しました。
※ ここでは簡略化するために上記の権限を付与していますが、範囲が広く、好ましい割当てではありません。運用ポリシーに合わせて適宜変更してください。
トリガーの設定
[設定] > [トリガー] > [トリガーを追加] からトリガーを追加します。
[トリガー を選択] で S3 を、[バケット] で作成しておいた「limited-cf-purge-by-file-countup」を、それ以外の項目はデフォルトのままにして、[追加] を押します。
オリジンとなる S3 にファイルをアップロードしてテストする
ここまで完了したら、CloudFront のオリジンとなる S3 にファイルをアップロードしましょう。コードソースで変更していなければファイル「.purge」をアップロードしてみてください。その後、CloudFront の該当のディストリビューションの画面に進み、新しく Invalidation が作成されていれば OK です。
動作しないときは、CloudWatch のログを確認するなどしてみてください。
お問い合わせ
環境構築やカスタマイズのご相談につきましては、お問い合わせフォームよりお問い合わせください。
- カテゴリー
- PowerCMS 5
- 技術情報
コメントを投稿する