PowerCMS™

PowerCMS ブログ

ホーム > PowerCMS ブログ > S3 同期の際に Lambda で自動的に CloudFront のキャッシュをパージする

2021年08月27日

S3 同期の際に Lambda で自動的に CloudFront のキャッシュをパージする

前回は、lsyncd を使ってコンテンツを S3 に同期する仕組みを構築する例 をご紹介しました。これにより、EC2 インスタンスで行われた更新を Amazon CloudFront のオリジンとなる S3 に同期することができるようになりますが、更新を反映するためには Amazon CloudFront のキャッシュをパージする必要があります。今回は、これを Lambda を使って自動的に行う方法をご紹介します。

前提

すでに S3 をオリジンとした CloudFront が稼働中の状態を想定しています。キャッシュのパージに一日あたりの上限を設けつつ、パージ実行のタイミングを明確にするため、(最上位階層かサブフォルダ内かに関わらず)特定の名前のファイルが更新された場合のみパージを行うものとします。

CloudFront ディストリビューションの ID を確認する

コンソールから、[CloudFront] > [Distributions] を表示した際の一覧の ID 列です。後述の手順で使うので、メモしておきましょう。

CloudFront ディストリビューション ID

キャッシュパージの回数を記録するための S3 バケットを作成する

コンソールから、[Amazon S3] > [バケット作成] から作成します。ここではバケット名を「limited-cf-purge-by-file-countup」としました。バケット名以外はデフォルトのまま [バケットを作成] ボタンを押します。

パージ回数記録のための S3 バケットの作成

Lambda 関数の作成

新しい関数を作成します。関数名はここでは「limited-cloudfront-purge-by-file」とし、ランタイムに「Python 3.8」を指定します。他の項目はデフォルトのまま [関数を作成] ボタンを押します。

新しい Lambda 関数の作成

関数が作成されたら、コードソースに下記をコピー&ペーストします。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 です。

新しく作成された Invalidation

動作しないときは、CloudWatch のログを確認するなどしてみてください。

お問い合わせ

環境構築やカスタマイズのご相談につきましては、お問い合わせフォームよりお問い合わせください。


カテゴリー
PowerCMS 5
技術情報

Recent Entries