AWS Lambdaを使用し、CloudfrontのInvalidationを走らせる

こんにちは。エンジニアの志村です。
先日assets on S3についての実装を行いました。   その際の記事は下記になります。

cluex-developers.hateblo.jp

今回はasset_syncにより、S3にassetファイルがアップロードされた段階でCloudfrontのInvalidationをLambdaを使用して走らせるという処理を実装したいと思います!

Invalidationとは

Cloudfrontのキャッシュを明示的に消す機能です。

dev.classmethod.jp

クラスメソッドさんの上記の記事が非常に分かりやすいかと思います。

キャッシュを使用するのに重要なポイントは適切なキャッシュ期間を設けることです。それを行わないと古いファイルがいつまで経っても配信され続けてしまいます。
特にassets on S3を使用する場合には、明示的にファイルをInvalidationしないといつまで経っても最新のassetsファイルがユーザーに配信されなくなります。
このような状況を防ぐために、S3にファイルが転送された段階で、assetsのキャッシュを消去する必要があります。

Lambdaの実装

ではLambdaの実装を始めていきます。

AWSコンソールからLambdaを選択します

「Create Lambda Function」を選択します

f:id:cluex-developers:20160916104010p:plain

今回はBlueprintは使用しないので「Skip」を選択します

f:id:cluex-developers:20160916104022p:plain

S3を選択します。

f:id:cluex-developers:20160916104040p:plain

項目 説明
Bucket assets用のBucketを選択
Event Type S3にassetsファイルがCreateされた段階でInvalidationを走らせたいので「Object Created(All)」を選択
Enable Trigger チェックを入れると、設定したイベントが走るようになります(production等で設定する場合は注意!)

※Prefix, Suffixは必要であれば入力して下さい。

LambdaFunctionを作成します

f:id:cluex-developers:20160916104141p:plain

項目 説明
Name 適当な名前を入力
Description 分かりやすい説明を入力
Runtime 今回はPythonにします

コードは下記のコードが非常に分かりやすかったのでそれを使用します。

www.cloudberrylab.com

※DistributionIDは自身のCloudfrontディストリビューションのIDを入力して下さい

from __future__ import print_function

import boto3
import time

def lambda_handler(event, context):
    for items in event["Records"]:
        path = "/" + items["s3"]["object"]["key"]
    print(path)
    client = boto3.client('cloudfront')
    invalidation = client.create_invalidation(DistributionId='ディストリビューションID',
        InvalidationBatch={
            'Paths': {
                'Quantity': 1,
                'Items': [path]
        },
        'CallerReference': str(time.time())
    })

因みにですが、boto3はPython用のAWS SDKです。 Lambda FunctionをPythonで書く際には必ずと言って良いほど良く使用します。 ドキュメントも充実しているので非常に使い勝手が良いと思います。

Boto 3 Documentation — Boto 3 Docs 1.4.0 documentation

ロールやその他の設定をします

「Lambda function handler and role」のRole→「Create a custom role」を選択します。 f:id:cluex-developers:20160916104432p:plain

そうすると下記のような画面が現れるので、下記のCloudfrontのInvalidationを許可するロールを作成します。 f:id:cluex-developers:20160916104616p:plain

下記のようなポリシードキュメントになります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
        "Effect": "Allow",
        "Action": [
            "cloudfront:CreateInvalidation"
        ],
        "Resource": [
            "*"
        ]
    }
  ]
}

最後に「Create function」を押下すれば完成です!

使い方

asset_syncでデプロイすると勝手にInvalidationが走ってくれます。 下記の画面で確認が出来ます。

AWSコンソールからCloudfrontを選択します

該当するディストリビューションのIDを選択します

f:id:cluex-developers:20160916104912p:plain

「Invalidations」タブを選択すると、Invalidationsの状態が閲覧出来ます。ここでデプロイ直後にStatusがProgressとなっていればトリガーがきちんと走っています。

f:id:cluex-developers:20160916105140p:plain

以上になります。 キャッシュの扱いって本当難しいなーと感じますが、この様に自動化してしまえば特に意識することも少なくなって、よりCloudfrontが使いやすくなりますね。