S3 + CloudFrontでS3にファイルをアップロードしたら自動でキャッシュをクリアする

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。

Invalidation

In Progress。OK。

参考記事

参考にさせていただきました。ありがとうございましたm(_ _)m

本サイトはUXを悪くするevilなGoogle広告を消しました。応援してくださる方は おすすめガジェット を見ていってください!
よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次